Data Import
Let’s import our data into R now so that we can explore the data further.
First let’s just get a general sense of our data. We can do that using the glimpse() function of the dplyr package (it is also in the tibble package).
Observations: 5,880
Variables: 11
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2…
$ location_name <chr> "Global", "Global", "Global", "Global", "Global",…
$ rei_id <dbl> 111, 111, 112, 112, 113, 113, 114, 114, 115, 115,…
$ rei_name <chr> "Diet low in fruits", "Diet low in fruits", "Diet…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "All …
$ sex <chr> "Male", "Female", "Male", "Female", "Male", "Fema…
$ parameter <chr> "continuous", "continuous", "continuous", "contin…
$ mean <dbl> 8.703202e+01, 9.953182e+01, 1.975187e+02, 1.83233…
$ upper <dbl> 8.988734e+01, 1.023450e+02, 2.083679e+02, 1.92110…
$ lower <dbl> 8.452347e+01, 9.672140e+01, 1.887154e+02, 1.75401…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/d…
Observations: 88,200
Variables: 11
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2…
$ location_name <chr> "Global", "Global", "Global", "Global", "Global",…
$ rei_name <chr> "Diet low in fruits", "Diet low in fruits", "Diet…
$ age_group_id <dbl> 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 3…
$ age_group_name <chr> "25 to 29", "30 to 34", "35 to 39", "40 to 44", "…
$ sex <chr> "Male", "Male", "Male", "Male", "Male", "Male", "…
$ parameter <chr> "continuous", "continuous", "continuous", "contin…
$ mean <dbl> 68.54567, 72.62209, 76.73157, 81.03910, 88.79202,…
$ upper <dbl> 75.16806, 80.00433, 84.73205, 89.52747, 100.94301…
$ lower <dbl> 63.17081, 66.78018, 71.04691, 73.82734, 80.40971,…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/d…
Here we can tell that the sep_age_diet_data is much larger than the diet_data. There are 88,200 rows! The diet_data has only 5,880 rows. However, both files appear to have the same column structure with 11 variables each.
The skim() function of the skimr package is also really helpful for getting a general sense of your data.
Data summary
| Name |
diet_data |
| Number of rows |
5880 |
| Number of columns |
11 |
| _______________________ |
|
| Column type frequency: |
|
| character |
6 |
| numeric |
5 |
| ________________________ |
|
| Group variables |
None |
Variable type: character
| location_name |
0 |
1 |
4 |
32 |
0 |
196 |
0 |
| rei_name |
0 |
1 |
16 |
39 |
0 |
15 |
0 |
| age_group_name |
0 |
1 |
18 |
18 |
0 |
1 |
0 |
| sex |
0 |
1 |
4 |
6 |
0 |
2 |
0 |
| parameter |
0 |
1 |
10 |
10 |
0 |
1 |
0 |
| unit |
0 |
1 |
5 |
11 |
0 |
2 |
0 |
Variable type: numeric
| year_id |
0 |
1 |
2017.00 |
0.00 |
2017 |
2017.00 |
2017.00 |
2017.00 |
2017.00 |
▁▁▇▁▁ |
| rei_id |
0 |
1 |
133.67 |
53.93 |
111 |
114.00 |
118.00 |
123.00 |
333.00 |
▇▁▁▁▁ |
| mean |
0 |
1 |
34.81 |
60.13 |
0 |
0.45 |
8.38 |
42.66 |
566.69 |
▇▁▁▁▁ |
| upper |
0 |
1 |
37.94 |
65.30 |
0 |
0.49 |
9.22 |
46.54 |
624.23 |
▇▁▁▁▁ |
| lower |
0 |
1 |
31.93 |
55.40 |
0 |
0.42 |
7.52 |
39.21 |
513.22 |
▇▁▁▁▁ |
Notice how there is a column about the values that are missing. It looks like our data is very complete and we do not have any missing data. We also get a sense about the size of our data.
The n_unqiue column shows us the number of unqiue values for each of our columns.
Let’s take a look at sep_age_diet_data.
Data summary
| Name |
sep_age_diet_data |
| Number of rows |
88200 |
| Number of columns |
11 |
| _______________________ |
|
| Column type frequency: |
|
| character |
6 |
| numeric |
5 |
| ________________________ |
|
| Group variables |
None |
Variable type: character
| location_name |
0 |
1 |
4 |
32 |
0 |
196 |
0 |
| rei_name |
0 |
1 |
16 |
39 |
0 |
15 |
0 |
| age_group_name |
0 |
1 |
7 |
8 |
0 |
15 |
0 |
| sex |
0 |
1 |
4 |
6 |
0 |
2 |
0 |
| parameter |
0 |
1 |
10 |
10 |
0 |
1 |
0 |
| unit |
0 |
1 |
5 |
11 |
0 |
2 |
0 |
Variable type: numeric
| year_id |
0 |
1 |
2017.00 |
0.00 |
2017 |
2017.00 |
2017.00 |
2017.00 |
2017.00 |
▁▁▇▁▁ |
| age_group_id |
0 |
1 |
32.87 |
54.46 |
10 |
13.00 |
17.00 |
30.00 |
235.00 |
▇▁▁▁▁ |
| mean |
0 |
1 |
39.84 |
63.86 |
0 |
0.56 |
10.80 |
52.63 |
604.01 |
▇▁▁▁▁ |
| upper |
0 |
1 |
48.07 |
78.38 |
0 |
0.70 |
13.55 |
59.96 |
806.98 |
▇▁▁▁▁ |
| lower |
0 |
1 |
33.46 |
54.54 |
0 |
0.42 |
8.46 |
44.87 |
639.06 |
▇▁▁▁▁ |
We can see that there are many more rows in this dataset.
Let’s take a look at the different dietary risk factors considered. To do this we will use the distinct() function of the dplyr package.
This function grabs only the distinct or unique rows from a given variable (rei_name, in our case) of a given data frame (diet_data, in our case).
# A tibble: 15 x 1
rei_name
<chr>
1 Diet low in fruits
2 Diet low in vegetables
3 Diet low in whole grains
4 Diet low in nuts and seeds
5 Diet low in milk
6 Diet high in red meat
7 Diet high in processed meat
8 Diet high in sugar-sweetened beverages
9 Diet low in fiber
10 Diet low in seafood omega-3 fatty acids
11 Diet low in polyunsaturated fatty acids
12 Diet high in trans fatty acids
13 Diet high in sodium
14 Diet low in calcium
15 Diet low in legumes
We will be using the %>% pipe for sequential steps in our code later on. This will make more sense when we have multiple sequential steps using the same data object.
We could do the same code as above using this notation. For example we first grab the diet_data, then we select the distinct values of the rei_name variable.
# A tibble: 15 x 1
rei_name
<chr>
1 Diet low in fruits
2 Diet low in vegetables
3 Diet low in whole grains
4 Diet low in nuts and seeds
5 Diet low in milk
6 Diet high in red meat
7 Diet high in processed meat
8 Diet high in sugar-sweetened beverages
9 Diet low in fiber
10 Diet low in seafood omega-3 fatty acids
11 Diet low in polyunsaturated fatty acids
12 Diet high in trans fatty acids
13 Diet high in sodium
14 Diet low in calcium
15 Diet low in legumes
Ok, so that gives us an idea of what dietary factors we can explore.
Let’s see if the location_name values are the same between both csv files. To do this we will use the setequal() function of dplyr.
[1] TRUE
Ok, we got the value of TRUE, so it looks like the same locations are in both files.
Note: In this case were comparing two different objects so using the pipe is not as useful.
Let’s take a look at the locations included in the data.
OK, so there are global values, as well as values for 185 countries.
Let’s take a look at the data when we order it by the mean consumption rate column:
Observations: 5,880
Variables: 11
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2…
$ location_name <chr> "Lebanon", "Lebanon", "Italy", "Turkey", "Kazakhs…
$ rei_id <dbl> 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,…
$ rei_name <chr> "Diet high in trans fatty acids", "Diet high in t…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "All …
$ sex <chr> "Male", "Female", "Male", "Male", "Male", "Male",…
$ parameter <chr> "continuous", "continuous", "continuous", "contin…
$ mean <dbl> 0.000727793, 0.000819837, 0.001357473, 0.00141107…
$ upper <dbl> 0.000892791, 0.001007998, 0.001491509, 0.00172748…
$ lower <dbl> 0.000585340, 0.000670438, 0.001233583, 0.00113497…
$ unit <chr> "%energy/day", "%energy/day", "%energy/day", "%en…
Ok, so it looks like people in Lebanon dont eat very many trans fatty acids.
Let’s also figure out how many values there are in each age group of the data that is separated by age.
# A tibble: 15 x 2
age_group_name n
<chr> <int>
1 25 to 29 5880
2 30 to 34 5880
3 35 to 39 5880
4 40 to 44 5880
5 45 to 49 5880
6 50 to 54 5880
7 55 to 59 5880
8 60 to 64 5880
9 65 to 69 5880
10 70 to 74 5880
11 75 to 79 5880
12 80 to 84 5880
13 85 to 89 5880
14 90 to 94 5880
15 95 plus 5880
That’s a lot of values!
Let’s look a bit deeper to try to understand why. We can use the count function again but get the number of values for each category within sex, age_group_name and location_name of the data.
# A tibble: 5,880 x 4
sex age_group_name location_name n
<chr> <chr> <chr> <int>
1 Female 25 to 29 Afghanistan 15
2 Female 25 to 29 Albania 15
3 Female 25 to 29 Algeria 15
4 Female 25 to 29 American Samoa 15
5 Female 25 to 29 Andorra 15
6 Female 25 to 29 Angola 15
7 Female 25 to 29 Antigua and Barbuda 15
8 Female 25 to 29 Argentina 15
9 Female 25 to 29 Armenia 15
10 Female 25 to 29 Australia 15
# … with 5,870 more rows
Ok, so it looks like there are probably the consumption values for each of the different dietary factors(which there were 15 different factors) for each age group, for each gender, and for each country.
We can confirm this by filtering the data to one of the age groups, for a single gender, and for a single location.
# A tibble: 15 x 11
year_id location_name rei_name age_group_id age_group_name sex
<dbl> <chr> <chr> <dbl> <chr> <chr>
1 2017 Afghanistan Diet lo… 10 25 to 29 Fema…
2 2017 Afghanistan Diet lo… 10 25 to 29 Fema…
3 2017 Afghanistan Diet lo… 10 25 to 29 Fema…
4 2017 Afghanistan Diet lo… 10 25 to 29 Fema…
5 2017 Afghanistan Diet lo… 10 25 to 29 Fema…
6 2017 Afghanistan Diet hi… 10 25 to 29 Fema…
7 2017 Afghanistan Diet hi… 10 25 to 29 Fema…
8 2017 Afghanistan Diet hi… 10 25 to 29 Fema…
9 2017 Afghanistan Diet lo… 10 25 to 29 Fema…
10 2017 Afghanistan Diet lo… 10 25 to 29 Fema…
11 2017 Afghanistan Diet lo… 10 25 to 29 Fema…
12 2017 Afghanistan Diet hi… 10 25 to 29 Fema…
13 2017 Afghanistan Diet hi… 10 25 to 29 Fema…
14 2017 Afghanistan Diet lo… 10 25 to 29 Fema…
15 2017 Afghanistan Diet lo… 10 25 to 29 Fema…
# … with 5 more variables: parameter <chr>, mean <dbl>, upper <dbl>,
# lower <dbl>, unit <chr>
Let’s also get the data from the PDF of the paper so that we can calculate consumption of these dietary factors as percentage of daily requirement, which would be more interpretable.
We are interested in this table on page 3:

First let’s import the PDF using the pdftools package.
We can use the base summary() function to get a sense of what the data looks like. By base we mean that these functions are part of the base package and are loaded automatically.Thus library(base) is not required.
Length Class Mode
15 character character
We can see that we have 15 different character strings. Each one contains the text on each of the 15 different pages of the PDF.
Data Wrangling
Again, the table we are interested in is on the third page, so let’s grab just that portion of the PDF.

Length Class Mode
1 character character
chr " Articles\nin systolic blood pressure, and then estimated the Disease-specific deaths and disability-adjusted\nrelationship between change in systolic blood pressure life-years\nand disease outcomes.14 Data on disease-specific deaths and disability-adjusted\n life-years (DALYs) by age, sex, country, and year were\nOptimal level of intake "| __truncated__
Here we can see that the table object now contains the text from the 3rd page as a single large character string. However the text is difficult to read beacuse of the column structure in the pdf. Now let’s try to grab just the text in the table.
One way to approach this is to split the string by some pattern that we notice in the table.

Only the capitalized form of the word “Diet” apears to be within the table, and is not present in the preceding text (altough “diet” is). All the rows of interest of the table appear to start with the word “Diet”.

Let’s use the str_split() function of the stringr package to split the data within the object called tableby the word “Diet”. Only lines from page 3 that contain the word Diet will be selected (and not “diet” as this function is case-sensitive). Each section of the text that contians “Diet” will be split into individual pieces everytime the world “Diet” occurs and the word itself will be removed.
In this case we are also using the magrittr assignment pipe or double pipe that looks like this %<>%. This allows us use the table data as input to the later steps but also reassign the output to the same data object name.
Using the base::summary() and dplyr::glimpse() function we can see that we created a list of the rows in the table that contain the word “Diet”. We can see that we start with the row that contains “Diet low in fruits”.
Length Class Mode
[1,] 17 -none- character
List of 1
$ : chr [1:17] " "| __truncated__ " low in fruits Mean daily consumption of fruits (fresh, frozen, cooked, canned, or dried fruit"| __truncated__ " low in vegetables Mean daily consumption of vegetables (fresh, frozen, cooked, canned, or dried v"| __truncated__ " low in legumes Mean daily consumption of legumes (fresh, frozen, cooked, canned, or dried legu"| __truncated__ ...
RStudio creates really cheatsheets like this one which shows you all the major functions in stringr. You can download others here.

You can see that we could have also used the str_split_fixed() function which would also separate the substrings into different columns of a matrix, however we would need to know the number of substrings or pieces that we would like returned.
For more information about str_split() see here.
Let’s separte the values within the list using the base unlist function, this will allow us to easily select the different substrings within the object called table.
It’s important to realize that the first split will split the text before the first occurance of Data as the first value in the output. We could use the first() function of the dplyr package to look at this value. However, we will suppress the output as this is quite large.
Instead we can take a look at the second element of the list. using the nth() function of dplyr.
[1] " low in fruits Mean daily consumption of fruits (fresh, frozen, cooked, canned, or dried fruits, excluding 250 g (200–300) per day 94·9\n fruit juices and salted or pickled fruits)\n "
Indeed this looks like the first row of interest in our table:

Using the last() and the nth() functions of the dplyr package we can take a look at the last values of the list.
[1] " high in sodium 24 h urinary sodium measured in g per day 3 g (1–5) per day* 26·2\n *To reflect the uncertainty in existing evidence on optimal level of intake for sodium, 1–5 g per day was considered as the uncertainty range for the optimal level of sodium where less than 2·3 g per day is the\n intake level of sodium associated with the lowest level of blood pressure in randomised controlled trials and 4–5 g per day is the level of sodium intake associated with the lowest risk of cardiovascular disease in\n observational studies.\n Table: "
[1] "ary risk factor exposure definitions, optimal level, and data representativeness index, 1990–2017\nwww.thelancet.com Published online April 3, 2019 http://dx.doi.org/10.1016/S0140-6736(19)30041-8 3\n"

Therefore, we dont need this part of the table or the text before the table if we just want the consumption reccomendations.
So we will select the 2nd through the second to last of the substrings. Since we have 17 substrings, we will select the 2nd through the 16th. However a better way to do this rather than selecting by index, would be to select phrases that are unique to the text within the table that we want. We will use the str_subset() function of stringr package to select the table rows with consumption guidlines. Most of the rows have the phrase" Mean daily consumption“, however, there are other phrases for some of the rows, including”Mean daily intake" and “24 h sodium”
Notice that we speparate the different patterns to look for using vertical bar character “|” and that all of the patterns are within quotation marks together.
Question opportunity:
What other string patterns could you use to subset the rows of the table that we want?
Why might it be better to subset based on the text rather than the index?
Now the first row is what we want:
[1] " low in fruits Mean daily consumption of fruits (fresh, frozen, cooked, canned, or dried fruits, excluding 250 g (200–300) per day 94·9\n fruit juices and salted or pickled fruits)\n "
And the last row is what we want:
[1] " high in sodium 24 h urinary sodium measured in g per day 3 g (1–5) per day* 26·2\n *To reflect the uncertainty in existing evidence on optimal level of intake for sodium, 1–5 g per day was considered as the uncertainty range for the optimal level of sodium where less than 2·3 g per day is the\n intake level of sodium associated with the lowest level of blood pressure in randomised controlled trials and 4–5 g per day is the level of sodium intake associated with the lowest risk of cardiovascular disease in\n observational studies.\n Table: "
Notice that there the decimal points from the pdf are being recognized as an interpunct instead of a period or decimal. An interpunct is a centered dot, as opposed to a period or decimal that is aligned to the bottom of the line.
The interpunct was previously used to separate words in certain languages, like ancient Latin.
You can produce an interpunct on a mac like this:
It is important to replace these for later when we want these values to be converted from character strings to numeric. We will again use the stringr package. This time we will use the str_replace_all() function which replaces all instances of a pattern in an individual string. In this case we want to replace all instances of the interpunct with a decimal point.
Now we will try to split the strings for each row based on the presence of 2 spaces to create the columns of the table, as there appears to be larger than a space between the columns to create substrings. The substrings will be separated by quotes.

The second page of the stringr cheetsheet has more information about using “Special Characters” in stringr. For example \\s is interpreted as a space as the \\ indicates that the s should be interpreted as a special character and not simply the letter s. The {2,} indicates 2 or more spaces, while {2} would indicate exactly 2 spaces.
List of 15
$ : chr [1:6] " low in fruits" "Mean daily consumption of fruits (fresh, frozen, cooked, canned, or dried fruits, excluding" "250 g (200–300) per day" "94.9" ...
$ : chr [1:7] " low in vegetables" "Mean daily consumption of vegetables (fresh, frozen, cooked, canned, or dried vegetables," "360 g (290–430) per day" "94.9" ...
$ : chr [1:5] " low in legumes" "Mean daily consumption of legumes (fresh, frozen, cooked, canned, or dried legumes)" "60 g (50–70) per day" "94.9" ...
$ : chr [1:7] " low in whole grains" "Mean daily consumption of whole grains (bran, germ, and endosperm in their natural" "125 g (100–150) per day" "94.9" ...
$ : chr [1:5] " low in nuts and seeds" "Mean daily consumption of nut and seed foods" "21 g (16–25) per day" "94.9" ...
$ : chr [1:6] " low in milk" "Mean daily consumption of milk including non-fat, low-fat, and full-fat milk, excluding soy" "435 g (350–520) per day" "94.9" ...
$ : chr [1:6] " high in red meat" "Mean daily consumption of red meat (beef, pork, lamb, and goat, but excluding poultry, fish," "23 g (18–27) per day" "94.9" ...
$ : chr [1:6] " high in processed meat" "Mean daily consumption of meat preserved by smoking, curing, salting, or addition of" "2 g (0–4) per day" "36.9" ...
$ : chr [1:6] " high in sugar-sweetened Mean daily consumption of beverages with ≥50 kcal per 226.8 serving, including carbonated" "3 g (0–5) per day" "36.9" "beverages" ...
$ : chr [1:6] " low in fibre" "Mean daily intake of fibre from all sources including fruits, vegetables, grains, legumes, and" "24 g (19–28) per day" "94.9" ...
$ : chr [1:5] " low in calcium" "Mean daily intake of calcium from all sources, including milk, yogurt, and cheese" "1.25 g (1.00–1.50) per day" "94.9" ...
$ : chr [1:5] " low in seafood omega-3 Mean daily intake of eicosapentaenoic acid and docosahexaenoic acid" "250 mg (200–300) per day" "94.9" "fatty acids" ...
$ : chr [1:7] " low in polyunsaturated" "Mean daily intake of omega-6 fatty acids from all sources, mainly liquid vegetable oils," "11% (9–13) of total daily energy" "94.9" ...
$ : chr [1:6] " high in trans fatty acids" "Mean daily intake of trans fat from all sources, mainly partially hydrogenated vegetable oils" "0.5% (0.0–1.0) of total daily energy" "36.9" ...
$ : chr [1:8] " high in sodium" "24 h urinary sodium measured in g per day" "3 g (1–5) per day*" "26.2" ...
If we look closely, we can see that the sugar-sweetened beverage and the seafood category had only one space between the first and second columns - the columns about the dietary category and the one that describes in more detail what the consumption suggestion is about.
The values for these two columns appear to be together still in the same substring for these two categories. There are no quotation marks adjacent to the word "Mean".
Here you can see how the next substring should have started with the word "Mean" by the new inclusion of a quotation mark ".

We can add an extra space in front of the word "Mean" for these particular categories and then try splitting again.
Since we orginally split based on 2 or more spaces, we can just add a space in front of the word “Mean” for all the table strings and then try subsetting again.
[1] 9 12
We could also hust add a space in front of all the values of Mean in the table since the split was peformed based on 2 or more spaces. Thus the other elements in table would also be split just as before despite the additional space.
Looks better!
We want just the first (the food category) and third column (the optimal consumption amount suggested) for each row in the table.
We can use the map function of the purrr package to accomplish this.
The map function allows us to perform the same action multiple times across each element within an object.
This following will allow us to select the 1st or 3rd substring from each element of the table object.
[[1]]
[1] " low in fruits"
[[2]]
[1] " low in vegetables"
[[3]]
[1] " low in legumes"
[[4]]
[1] " low in whole grains"
[[5]]
[1] " low in nuts and seeds"
[[6]]
[1] " low in milk"
[[1]]
[1] "250 g (200–300) per day"
[[2]]
[1] "360 g (290–430) per day"
[[3]]
[1] "60 g (50–70) per day"
[[4]]
[1] "125 g (100–150) per day"
[[5]]
[1] "21 g (16–25) per day"
[[6]]
[1] "435 g (350–520) per day"
Now we will create a tibble using this data. However, currently both category and amount are of class list. To create a tibble we need to unlist the data to create vectors.
[1] "list"
[1] "character"
We could have done all of this at once in one command like this:
Now we will create a tibble, which is an important data frame structure in the tidyverse which allows us to use other packages in the tidyverse with our data.
We will name our tibble columns now as we create our tibble using the tibble() function of both the tidyr and the tibble packages, as names are required in tibbles.
# A tibble: 15 x 2
category amount
<chr> <chr>
1 " low in fruits" 250 g (200–300) per day
2 " low in vegetables" 360 g (290–430) per day
3 " low in legumes" 60 g (50–70) per day
4 " low in whole grains" 125 g (100–150) per day
5 " low in nuts and seeds" 21 g (16–25) per day
6 " low in milk" 435 g (350–520) per day
7 " high in red meat" 23 g (18–27) per day
8 " high in processed meat" 2 g (0–4) per day
9 " high in sugar-sweetened" 3 g (0–5) per day
10 " low in fibre" 24 g (19–28) per day
11 " low in calcium" 1.25 g (1.00–1.50) per day
12 " low in seafood omega-3" 250 mg (200–300) per day
13 " low in polyunsaturated" 11% (9–13) of total daily energy
14 " high in trans fatty acids" 0.5% (0.0–1.0) of total daily energy
15 " high in sodium" 3 g (1–5) per day*
Looking pretty good!
However, we want to separate the different amounts within the amount column.
Recall what the orginal table looked like: 
Separating values within a variable
We can use the tidyr::separate() function to separate the data within the amount column into three new columns based on the optimal level and the optimal range. We can separate the values based on the open parantheses "(" and the long dash "–" characters.
# A tibble: 6 x 4
category optimal lower upper
<chr> <chr> <chr> <chr>
1 " low in fruits" "250 g " 200 300) per day
2 " low in vegetables" "360 g " 290 430) per day
3 " low in legumes" "60 g " 50 70) per day
4 " low in whole grains" "125 g " 100 150) per day
5 " low in nuts and seeds" "21 g " 16 25) per day
6 " low in milk" "435 g " 350 520) per day
Let’s Also create a new variable/column in our tibble that indicates the direction that can be harmful for each dietary factor.
# A tibble: 15 x 5
direction food optimal lower upper
<chr> <chr> <chr> <chr> <chr>
1 " low" fruits "250 g " 200 300) per day
2 " low" vegetables "360 g " 290 430) per day
3 " low" legumes "60 g " 50 70) per day
4 " low" whole grains "125 g " 100 150) per day
5 " low" nuts and seeds "21 g " 16 25) per day
6 " low" milk "435 g " 350 520) per day
7 " high" red meat "23 g " 18 27) per day
8 " high" processed meat "2 g " 0 4) per day
9 " high" sugar-sweetened "3 g " 0 5) per day
10 " low" fibre "24 g " 19 28) per day
11 " low" calcium "1.25 g " 1.00 1.50) per day
12 " low" seafood omega-3 "250 mg " 200 300) per day
13 " low" polyunsaturated "11% " 9 13) of total daily energy
14 " high" trans fatty acids "0.5% " 0.0 1.0) of total daily energy
15 " high" sodium "3 g " 1 5) per day*
If we wanted to remove the direction variable we could use the purrr::modify_at() function:
Data cleaning with regular expressions
Ok, looking better, but we still need a bit of cleaning to remove symbols and extra words from the columns. Some of the extra symbols include: "%", ")" and the "*".
The "*" and the ")" are what we call metacharacters or regular expressions. These are characters that have special meanings.

Now we need the "\\" to indicate that we want these characters to be matched exactly and not interpreted as the meaning of the symbol.
See here for more info about regular expressions in R.
Also here we have a bit of an example using the str_count() function of stringr, which counts the number of instences of a character string. In this case we will look for individual characters but you could also search for words or phrases.
[1] "Testing for ts or\ttabs can be tricky.(yes, it really can!*)\n"
[1] 5
[1] 1
[1] 1
[1] 1
[1] 1
We also want to make a unit variable so that we can make sure that our units are consistent later.
[1] "250 g " "360 g " "60 g " "125 g " "21 g " "435 g " "23 g "
[8] "2 g " "3 g " "24 g " "1.25 g " "250 mg " "11% " "0.5% "
[15] "3 g "
Notice that the values that are percentages dont have spaces between the number and the unit. We can separate the optimal values by a space or a percent symbol "%" using "|" to indicate that we want to separate by either. In this case we will lose the “%” and will need to add it back to those values.
# A tibble: 15 x 6
direction food lower optimal unit upper
<chr> <chr> <chr> <chr> <chr> <chr>
1 " low" fruits 200 250 g 300) per day
2 " low" vegetables 290 360 g 430) per day
3 " low" legumes 50 60 g 70) per day
4 " low" whole grains 100 125 g 150) per day
5 " low" nuts and seeds 16 21 g 25) per day
6 " low" milk 350 435 g 520) per day
7 " high" red meat 18 23 g 27) per day
8 " high" processed meat 0 2 g 4) per day
9 " high" sugar-sweetened 0 3 g 5) per day
10 " low" fibre 19 24 g 28) per day
11 " low" calcium 1.00 1.25 g 1.50) per day
12 " low" seafood omega-3 200 250 mg 300) per day
13 " low" polyunsaturated 9 11 "" 13) of total daily ener…
14 " high" trans fatty acids 0.0 0.5 "" 1.0) of total daily ene…
15 " high" sodium 1 3 g 5) per day*
Great, so to now we will add “%” to the unit variable for the low in polyunsaturated and high in trans fatty acids rows.
First we need to replace the empty values with NA using the na_if() function of the dplyr package.
# A tibble: 15 x 6
direction food lower optimal unit upper
<chr> <chr> <chr> <chr> <chr> <chr>
1 " low" fruits 200 250 g 300) per day
2 " low" vegetables 290 360 g 430) per day
3 " low" legumes 50 60 g 70) per day
4 " low" whole grains 100 125 g 150) per day
5 " low" nuts and seeds 16 21 g 25) per day
6 " low" milk 350 435 g 520) per day
7 " high" red meat 18 23 g 27) per day
8 " high" processed meat 0 2 g 4) per day
9 " high" sugar-sweetened 0 3 g 5) per day
10 " low" fibre 19 24 g 28) per day
11 " low" calcium 1.00 1.25 g 1.50) per day
12 " low" seafood omega-3 200 250 mg 300) per day
13 " low" polyunsaturated 9 11 <NA> 13) of total daily ener…
14 " high" trans fatty acids 0.0 0.5 <NA> 1.0) of total daily ene…
15 " high" sodium 1 3 g 5) per day*
Then to replace the NA values, we can use the replace_na() function in the tidyr package and the mutate() function of dplyr to specify which values to replace, in this case the NA values within the variable unit. Essentially this variable gets reasigned with the new values, as we mostly think of the mutate() function as creating new variables.
# A tibble: 2 x 6
direction food lower optimal unit upper
<chr> <chr> <chr> <chr> <chr> <chr>
1 " low" polyunsaturated 9 11 % 13) of total daily energy
2 " high" trans fatty acids 0.0 0.5 % 1.0) of total daily ener…
Let’s also move unit to be the last column. We can use the select() and everything() functions of the dplyr package to do this.
Here you can see Hadley Wickham’s (Chief Scientist at RStudio) explanation for this behavior of select():
https://github.com/tidyverse/dplyr/issues/2838#issuecomment-306062800
To remove all of the remaining extra characters and words we will again use the stringr package. This time we will use the str_remove_all() function to remove all instances of these characters.
Nice! that’s pretty clean but we can do a bit more.
Data type conversion
One of the next things to notice about our data is the character classes of our variables.
Notice that the optimal amounts of consumption are currently of class character as indicated by the <chr> just below the column names / variable names of the guidelines tibble:
# A tibble: 15 x 6
direction food lower optimal upper unit
<chr> <chr> <chr> <chr> <chr> <chr>
1 " low" fruits 200 250 300 g
2 " low" vegetables 290 360 430 g
3 " low" legumes 50 60 70 g
4 " low" whole grains 100 125 150 g
5 " low" nuts and seeds 16 21 25 g
6 " low" milk 350 435 520 g
7 " high" red meat 18 23 27 g
8 " high" processed meat 0 2 4 g
9 " high" sugar-sweetened 0 3 5 g
10 " low" fibre 19 24 28 g
11 " low" calcium 1.00 1.25 1.50 g
12 " low" seafood omega-3 200 250 300 mg
13 " low" polyunsaturated 9 11 13 %
14 " high" trans fatty acids 0.0 0.5 1.0 %
15 " high" sodium 1 3 5 g
To convert these values to numeric we can use the mutate_at() function of the dplyr package.
The mutate_at() function allows us to perform a function on specific columns/variables within a tibble. We need to indicate which variables that we would like to convert using vars(). In this case if we look at the beginning of the guidelines tibble, we can see that optimal, lower and upper should be converted. As these three columns are sequential, we can simply put a : between optimal and upper to indicate that we want all the variables in between these columns to be converted.
# A tibble: 15 x 6
direction food lower optimal upper unit
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 " low" fruits 200 250 300 g
2 " low" vegetables 290 360 430 g
3 " low" legumes 50 60 70 g
4 " low" whole grains 100 125 150 g
5 " low" nuts and seeds 16 21 25 g
6 " low" milk 350 435 520 g
7 " high" red meat 18 23 27 g
8 " high" processed meat 0 2 4 g
9 " high" sugar-sweetened 0 3 5 g
10 " low" fibre 19 24 28 g
11 " low" calcium 1 1.25 1.5 g
12 " low" seafood omega-3 200 250 300 mg
13 " low" polyunsaturated 9 11 13 %
14 " high" trans fatty acids 0 0.5 1 %
15 " high" sodium 1 3 5 g
Great! Now these variables are of class <dbl> (stands for double) which indicates that they are numeric. Here is a link for more info on numeric classes in R.
If we had not replaced the "·" interpunct values to a period conversion from character to numeric will be problematic and will result in NA values.
Data value reassignments
We seem to have lost the word "beverages" from the "sugar-sweetened beverages" category, as well as "fatty acids" from the "seafood omega 3 fatty acids", and the "polyunsaturated fatty acids" categories as the full category name was listed on two lines within the table. We would like to replace these values with the full name.
To select the food column we will show you several options. Only a couple will work well with reassigning the data in that particular variable within guidelines without assigning an intermediate data object. We will look using mutate_at(), pull(), select(), and brackets [,c("variable name")].
The bracket option and the select() option will grab a tibble (data frame) version of the food column out of guidelines. However we can’t start commands with select for assignments.
# A tibble: 15 x 1
food
<chr>
1 fruits
2 vegetables
3 legumes
4 whole grains
5 nuts and seeds
6 milk
7 red meat
8 processed meat
9 sugar-sweetened
10 fibre
11 calcium
12 seafood omega-3
13 polyunsaturated
14 trans fatty acids
15 sodium
# A tibble: 15 x 1
food
<chr>
1 fruits
2 vegetables
3 legumes
4 whole grains
5 nuts and seeds
6 milk
7 red meat
8 processed meat
9 sugar-sweetened
10 fibre
11 calcium
12 seafood omega-3
13 polyunsaturated
14 trans fatty acids
15 sodium
pull() in contrast, will grab the vector version of the food data:
[1] "fruits" "vegetables" "legumes"
[4] "whole grains" "nuts and seeds" "milk"
[7] "red meat" "processed meat" "sugar-sweetened"
[10] "fibre" "calcium" "seafood omega-3"
[13] "polyunsaturated" "trans fatty acids" "sodium"
The pull function can be very useful when combined with other functions (for example you typically want to use a vector with the str_replace() function), but just like select, we can’t start assignments with pull().
This is not possible and will result in an error:
This will only print the result, but not reassign the food variable values:
[1] "fruits" "vegetables"
[3] "legumes" "whole grains"
[5] "nuts and seeds" "milk"
[7] "red meat" "processed meat"
[9] "sugar-sweetened beverages" "fibre"
[11] "calcium" "seafood omega-3"
[13] "polyunsaturated" "trans fatty acids"
[15] "sodium"
Using select() would work as well to print the result (although the result structure is different):
[1] "c(\"fruits\", \"vegetables\", \"legumes\", \"whole grains\", \"nuts and seeds\", \"milk\", \"red meat\", \"processed meat\", \"sugar-sweetened beverages\", \"fibre\", \"calcium\", \"seafood omega-3\", \"polyunsaturated\", \"trans fatty acids\", \"sodium\")"
Question opportunity:
Why do these commands not reassign the food variable values?
The bracket option is great alternative and allows us to reassign the values within guidelines easily
# A tibble: 15 x 6
direction food lower optimal upper unit
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 " low" fruits 200 250 300 g
2 " low" vegetables 290 360 430 g
3 " low" legumes 50 60 70 g
4 " low" whole grains 100 125 150 g
5 " low" nuts and seeds 16 21 25 g
6 " low" milk 350 435 520 g
7 " high" red meat 18 23 27 g
8 " high" processed meat 0 2 4 g
9 " high" sugar-sweetened beverages 0 3 5 g
10 " low" fibre 19 24 28 g
11 " low" calcium 1 1.25 1.5 g
12 " low" seafood omega-3 fatty acids 200 250 300 mg
13 " low" polyunsaturated 9 11 13 %
14 " high" trans fatty acids 0 0.5 1 %
15 " high" sodium 1 3 5 g
Finally, the best option is probably the mutate_at() function from dplyr. In this case we need to include ~ in front of the function that we would like to use on the values in our food variables. We also include . as a replacement to reference the data that we want to use within str_replace() (which in this case is the food variable values of guidelines).
Notice we didn’t need this when we previously use mutate_at() with the as.numeric() function. This is becuase the str_replace() function requires us to specify what data we are using as one of the arguments, while as.numeric() does not.
# A tibble: 15 x 6
direction food lower optimal upper unit
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 " low" fruits 200 250 300 g
2 " low" vegetables 290 360 430 g
3 " low" legumes 50 60 70 g
4 " low" whole grains 100 125 150 g
5 " low" nuts and seeds 16 21 25 g
6 " low" milk 350 435 520 g
7 " high" red meat 18 23 27 g
8 " high" processed meat 0 2 4 g
9 " high" sugar-sweetened beverages 0 3 5 g
10 " low" fibre 19 24 28 g
11 " low" calcium 1 1.25 1.5 g
12 " low" seafood omega-3 fatty acids 200 250 300 mg
13 " low" polyunsaturated fatty acids 9 11 13 %
14 " high" trans fatty acids 0 0.5 1 %
15 " high" sodium 1 3 5 g
This might be considered a better option because it is more readible as to where the food data came from that we are replacing values within.
There is one last minor detail… the direction variable has leading spaces still. We can use str_trim() to fix that!
# A tibble: 15 x 6
direction food lower optimal upper unit
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low fruits 200 250 300 g
2 low vegetables 290 360 430 g
3 low legumes 50 60 70 g
4 low whole grains 100 125 150 g
5 low nuts and seeds 16 21 25 g
6 low milk 350 435 520 g
7 high red meat 18 23 27 g
8 high processed meat 0 2 4 g
9 high sugar-sweetened beverages 0 3 5 g
10 low fibre 19 24 28 g
11 low calcium 1 1.25 1.5 g
12 low seafood omega-3 fatty acids 200 250 300 mg
13 low polyunsaturated fatty acids 9 11 13 %
14 high trans fatty acids 0 0.5 1 %
15 high sodium 1 3 5 g
OK! Now we know how much of each dietary factor we generally need for optimal health according to the guidelines used in this article.
We would like to see how the mean consumption rates for the different groups of people compared to the optimal intake guidelines.
One way we could do this is to calculate a consumption percentage of the optimal value.
To calculate this it would be helpful to put the guideline amounts with the average consumption rates into the same tibble, especially because the observed consumption data (diet_data and sep_age_diet_data) are very different dimensions from the guidelines data.
In order to create a tibble with our observed consumption rates with the suggested consumption rates, we will join our data using dplyr. In order to do so it is important that our different datasets have the same values. So let’s first assess if that is the case.
Comparing data
# A tibble: 15 x 1
rei_name
<chr>
1 Diet low in fruits
2 Diet low in vegetables
3 Diet low in whole grains
4 Diet low in nuts and seeds
5 Diet low in milk
6 Diet high in red meat
7 Diet high in processed meat
8 Diet high in sugar-sweetened beverages
9 Diet low in fiber
10 Diet low in seafood omega-3 fatty acids
11 Diet low in polyunsaturated fatty acids
12 Diet high in trans fatty acids
13 Diet high in sodium
14 Diet low in calcium
15 Diet low in legumes
# A tibble: 15 x 1
food
<chr>
1 fruits
2 vegetables
3 legumes
4 whole grains
5 nuts and seeds
6 milk
7 red meat
8 processed meat
9 sugar-sweetened beverages
10 fibre
11 calcium
12 seafood omega-3 fatty acids
13 polyunsaturated fatty acids
14 trans fatty acids
15 sodium
We can see that we need to remove the "Diet low in" and "Diet high in" phrases from the observed consumption data.
Also let’s double check that the two observed files have the same exact values for dietary factor names.
We can use the setequal() function from dplyr to check that the unique values for rei_name are the same for both diet_data and sep_age_diet_data.
[1] TRUE
Great!
Note that the default of the set_equal function ignores the order of values in rows. So we still dont know if the order is the same.
We can check using the all_equal function of dplyr which reports back clues about what might be different if anything. Importantly we are including ignore_row_order = FALSE as the default is TRUE.
[1] TRUE
Looks like they are also in the same order.
Note that if any of the values are different all_equal() will first report this and will not report that the rows are in a different order.
Here is a toy example about how the three comparison functions(setequal(), all_equal() (also all.equal() for tbl_df), and setdiff()) work in dplyr.
It’s important to realize that row order is ignored by bothsetequal() and setdiff().
Now let’s compare two tibbles that have different row orders and differnt values.
Here are our tibbles to compare:
# A tibble: 4 x 1
test
<chr>
1 A
2 B
3 AC
4 D
# A tibble: 4 x 1
test
<chr>
1 A
2 D
3 AG
4 B
[1] "tbl_df" "tbl" "data.frame"
Since we are using tibbles, which are of class tbl_df we can use either all_equal or all.equal().
[1] "Rows in x but not y: 3. Rows in y but not x: 3. "
[1] "Rows in x but not y: 3. Rows in y but not x: 3. "
[1] "Rows in x but not y: 3. Rows in y but not x: 3. "
[1] "Rows in x but not y: 3. Rows in y but not x: 3. "
[1] FALSE
# A tibble: 1 x 1
test
<chr>
1 AC
# A tibble: 1 x 1
test
<chr>
1 AG
Now let’s make it so that only the order is different:
# A tibble: 4 x 1
test
<chr>
1 A
2 B
3 AC
4 D
# A tibble: 4 x 1
test
<chr>
1 A
2 D
3 AC
4 B
[1] TRUE
[1] "Same row values, but different order"
[1] TRUE
# A tibble: 0 x 1
# … with 1 variable: test <chr>
If we have different column/variable names this makes comparisons more challenging:
[1] "Cols in y but not x: `test2`. " "Cols in x but not y: `test`. "
[1] "Cols in y but not x: `test2`. " "Cols in x but not y: `test`. "
[1] FALSE
Ok, let’s keep going with our data.
How similar are the guidelines tibble and the observed consumption tibbles?
[1] FALSE
Ok, looks like we have some different values.
Let’s use the setdiff function to get more information about what is different between the values.
:( That wont work. This is because setdiff() requires that the colnames are the same in the objects that we are comparing.
We can use the rename() of dplyr function to do this. We list the value that we want to change to first. We find “food” more intuitive so we are going to change “rei_name” to “food” for the diet_data and the sep_age_diet_data
Great, now we know that the fiber value appears to be different between the two.
# A tibble: 1 x 1
food
<chr>
1 fibre
Changing the order of the objects, we can see that in the table from the article that we used to create guidelines, “fibre” the British spelling is used in contrast to the dataset which uses the American spelling “fiber”.
Let’s stick with the American spelling, so we will replace "fibre" in the guideline tibble. Again, we have two options for doing this:
# A tibble: 1 x 6
direction food lower optimal upper unit
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low fiber 19 24 28 g
Now let’s check again to see that our food values match between the guidelines and the observed consumption data tibbles.
# A tibble: 0 x 1
# … with 1 variable: food <chr>
# A tibble: 0 x 1
# … with 1 variable: food <chr>
Great! There are no differences :)
Joining data
Now we can put our guideline data together with the diet_data and the sep_age_diet_data.
Remeber that the food data in our guidelines tibble is not necessarily in the same order as that of the consumption data tibbles. Thus this could be a problem if we decided to expand the guidelines rows (to repeat for the number of fruit observations etc.) and add them to our observed consumption tibbles.

In that case we could use the arrange() function of dplyr to sort the data alphabetically.
However, we will instead use a joining function of dplyr. These functions combine the data together based on common values. There are a variety of options.

In our case we would like to retain all of the values of diet_data and sep_age_diet_data. We would like to add new columns of values to these tibbles that correspond to the guideline information about amounts of consumption for each food type in the guidelines tibble. We shouldn’t have any values of food in guidelines that dont match, so we will not get any NA values. Therefore, in our case any of the mutating join functions should result in the same output.
It’s important to check if we have any overlapping variable names before we join the data. We can use the base R function names() and the intersect() function of the dplyr package for this.
[1] "food" "upper" "lower" "unit"
So it looks like the "upper" , "lower" and "unit" variable names are overlapping. Therefore, to distinguish the names later we will rename the guideline "upper" , "lower" and "unit" variables.
We will again use the rename function from the dplyr package. We can list multiple variables to rename and separate each with a comma.
# A tibble: 15 x 6
direction food lower_optimal optimal upper_optimal unit_optimal
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low fruits 200 250 300 g
2 low vegetables 290 360 430 g
3 low legumes 50 60 70 g
4 low whole grains 100 125 150 g
5 low nuts and see… 16 21 25 g
6 low milk 350 435 520 g
7 high red meat 18 23 27 g
8 high processed me… 0 2 4 g
9 high sugar-sweete… 0 3 5 g
10 low fiber 19 24 28 g
11 low calcium 1 1.25 1.5 g
12 low seafood omeg… 200 250 300 mg
13 low polyunsatura… 9 11 13 %
14 high trans fatty … 0 0.5 1 %
15 high sodium 1 3 5 g
It’s also a good idea to check our units to make sure they are the same for both guidelines and the observed consumption tibbles: diet_and_guidelines and all_age_diet_and_guidelines.
Let’s take a look with the count() function of dplyr.
# A tibble: 15 x 9
unit food n unit1 food1 n1 unit_optimal food2 n2
<chr> <chr> <int> <chr> <chr> <int> <chr> <chr> <int>
1 %ener… polyunsa… 392 %ener… polyuns… 5880 % polyuns… 1
2 %ener… trans fa… 392 %ener… trans f… 5880 % trans f… 1
3 g/day calcium 392 g/day calcium 5880 g calcium 1
4 g/day fiber 392 g/day fiber 5880 g fiber 1
5 g/day fruits 392 g/day fruits 5880 g fruits 1
6 g/day legumes 392 g/day legumes 5880 g legumes 1
7 g/day milk 392 g/day milk 5880 g milk 1
8 g/day nuts and… 392 g/day nuts an… 5880 g nuts an… 1
9 g/day processe… 392 g/day process… 5880 g process… 1
10 g/day red meat 392 g/day red meat 5880 g red meat 1
11 g/day seafood … 392 g/day seafood… 5880 g sodium 1
12 g/day sodium 392 g/day sodium 5880 g sugar-s… 1
13 g/day sugar-sw… 392 g/day sugar-s… 5880 g vegetab… 1
14 g/day vegetabl… 392 g/day vegetab… 5880 g whole g… 1
15 g/day whole gr… 392 g/day whole g… 5880 mg seafood… 1
We can see that the only potential issue is the seafood omega-3 fatty acids data which is in g/day for the observed data(diet_data and all_age_diet_and_guidelines), but the unit is mg/day in the guidelines data.
We can account for this by dividing the guideline seafood omega-3 fatty acids data by 1000 to convert it to grams from milligrams.
To do this we will use the if_else() function in the dplyr package. This allows us to specify a condition (in this case if the unit is "mg"), as well as values if this is codition is met (true), or if the condition is not met (false). In the following we mutate the values in each of the guideline numeric columns (lower, optimal and upper) one at a time. When we refer to lower for example we refer to the values in the column/varaible. So if the condition is not met, then the original value is retained. We will also replace "mg" with "g" after everything is converted to grams.
guidelines%<>% mutate(lower_optimal = if_else(
condition = unit_optimal=="mg",
true = lower_optimal/1000,
false = lower_optimal))
guidelines%<>% mutate(optimal = if_else(
condition = unit_optimal=="mg",
true = optimal/1000,
false = optimal))
guidelines%<>% mutate(upper_optimal = if_else(
condition = unit_optimal=="mg",
true = upper_optimal/1000,
false = upper_optimal))
guidelines%<>% mutate(unit_optimal = if_else(
condition = unit_optimal=="mg",
true = "g",
false = unit_optimal))
#or this:
# guidelines%<>%
# mutate_at(vars(unit_optimal),
# ~str_replace(
# string = .,
# pattern = "mg",
# replacement = "g"))
guidelines
# A tibble: 15 x 6
direction food lower_optimal optimal upper_optimal unit_optimal
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low fruits 200 250 300 g
2 low vegetables 290 360 430 g
3 low legumes 50 60 70 g
4 low whole grains 100 125 150 g
5 low nuts and see… 16 21 25 g
6 low milk 350 435 520 g
7 high red meat 18 23 27 g
8 high processed me… 0 2 4 g
9 high sugar-sweete… 0 3 5 g
10 low fiber 19 24 28 g
11 low calcium 1 1.25 1.5 g
12 low seafood omeg… 0.2 0.25 0.3 g
13 low polyunsatura… 9 11 13 %
14 high trans fatty … 0 0.5 1 %
15 high sodium 1 3 5 g
THIS IS WORK to try to mutate all at once… can delete or keep working on…
#guidelines %>% mutate_if(str_detect(guidelines$unit, "mg") & is.numeric, ~.+2)
#https://stackoverflow.com/questions/51877611/can-i-combine-a-dplyr-mutate-at-mutate-if-statement
#https://github.com/tidyverse/dplyr/issues/631
#WORK
#if numeric and unit = mg??
# guidelines %>%
# mutate_at(filter(guidelines,food == "seafood omega-3 fatty acids"),vars(lower:upper), funs(./1000))
#
# guidelines %>%
# if_else(unit == "mg", mutate_at(list(lower:upper),if_else(unit == "mg", true = funs(./1000), false = .)))
# mutate_at(filter(guidelines,food == "seafood omega-3 fatty #acids"),vars(lower:upper), funs(./1000))
# guidelines %>%
# filter(food == "seafood omega-3 fatty acids")%>%
# mutate_at(vars(lower:upper), funs(./1000))
#
# guidelines %>%
# if_else(unit == "mg", mutate_at(list(lower:upper),if_else(unit == "mg", true = funs(./1000), false = .)))
# guidelines%>%
# mutate_at(vars(lower:upper), funs(ifelse(unit=="mg", TRUE/1000, TRUE)))
#
#
# mutate(cars, dist = ifelse(speed==4, dist*100, dist))
#
#
# guidelines[c("seafood omega-3 fatty acids"),]
# guidelines[c("seafood omega-3 fatty acids"),] <-guidelines %>%
# filter(food == "seafood omega-3 fatty acids")%>%
# mutate_at(vars(lower:upper), funs(10*.))
#
# cars<-mutate(cars, dist2 = dist)
# mutate(cars, dist = ifelse(speed==4, dist*100, dist))
guidelines %>%
filter(food == "seafood omega-3 fatty acids")%>%
mutate_at(vars(lower_optimal:upper_optimal), funs(./1000))
# A tibble: 1 x 6
direction food lower_optimal optimal upper_optimal unit_optimal
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low seafood omega… 0.0002 0.00025 0.000300 g
# type <- c(1:4)
# year1 <- c(1:4)
# year2 <- c(1:4)
# year3 <- c(1:4)
# data <- data.frame(type, year1, year2, year3)
#
#
# newdata <- data %>%
# gather(., year, value, year1:year3) %>%
# mutate(newvalue = ifelse(type > 2, value * 2, value)) %>%
# select(-value) %>%
# spread(., year, newvalue)
#
# Df %>%
# mutate_all(
# funs(case_when(
# . == "1" ~ 1*.,
# . == "2" ~ 2*.,
# . == "3" ~ 3*.))) %>%
# mutate(rowmax = pmax(!!!rlang::syms(names(.))))
#
# df %>% mutate_at(vars(a:c), funs(ifelse(is.na(d) | d == 0, NA, .)))
#
#
#
# msleep %>%
# select(name, sleep_total) %>%
# mutate(sleep_total_min = sleep_total * 60)
Now we are ready to join the data!
Agian, we would like to add new columns of values to diet_data and all_age_diet_and_guidelines that correspond to the guideline information about amounts of consumption for each food type in the guidelines tibble. So we will join the data based on the food variable values.
Observations: 5,880
Variables: 16
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2…
$ location_name <chr> "Global", "Global", "Global", "Global", "Global",…
$ rei_id <dbl> 111, 111, 112, 112, 113, 113, 114, 114, 115, 115,…
$ food <chr> "fruits", "fruits", "vegetables", "vegetables", "…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "All …
$ sex <chr> "Male", "Female", "Male", "Female", "Male", "Fema…
$ parameter <chr> "continuous", "continuous", "continuous", "contin…
$ mean <dbl> 8.703202e+01, 9.953182e+01, 1.975187e+02, 1.83233…
$ upper <dbl> 8.988734e+01, 1.023450e+02, 2.083679e+02, 1.92110…
$ lower <dbl> 8.452347e+01, 9.672140e+01, 1.887154e+02, 1.75401…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/d…
$ direction <chr> "low", "low", "low", "low", "low", "low", "low", …
$ lower_optimal <dbl> 200.0, 200.0, 290.0, 290.0, 100.0, 100.0, 16.0, 1…
$ optimal <dbl> 250.00, 250.00, 360.00, 360.00, 125.00, 125.00, 2…
$ upper_optimal <dbl> 300.0, 300.0, 430.0, 430.0, 150.0, 150.0, 25.0, 2…
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", "g",…
Observations: 88,200
Variables: 16
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2…
$ location_name <chr> "Global", "Global", "Global", "Global", "Global",…
$ food <chr> "fruits", "fruits", "fruits", "fruits", "fruits",…
$ age_group_id <dbl> 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 3…
$ age_group_name <chr> "25 to 29", "30 to 34", "35 to 39", "40 to 44", "…
$ sex <chr> "Male", "Male", "Male", "Male", "Male", "Male", "…
$ parameter <chr> "continuous", "continuous", "continuous", "contin…
$ mean <dbl> 68.54567, 72.62209, 76.73157, 81.03910, 88.79202,…
$ upper <dbl> 75.16806, 80.00433, 84.73205, 89.52747, 100.94301…
$ lower <dbl> 63.17081, 66.78018, 71.04691, 73.82734, 80.40971,…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", "g/d…
$ direction <chr> "low", "low", "low", "low", "low", "low", "low", …
$ lower_optimal <dbl> 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,…
$ optimal <dbl> 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,…
$ upper_optimal <dbl> 300, 300, 300, 300, 300, 300, 300, 300, 300, 300,…
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", "g",…
It’s always a good idea to check that the values are what you expect after merging.
# A tibble: 15 x 3
food optimal n
<chr> <dbl> <int>
1 calcium 1.25 392
2 fiber 24 392
3 fruits 250 392
4 legumes 60 392
5 milk 435 392
6 nuts and seeds 21 392
7 polyunsaturated fatty acids 11 392
8 processed meat 2 392
9 red meat 23 392
10 seafood omega-3 fatty acids 0.25 392
11 sodium 3 392
12 sugar-sweetened beverages 3 392
13 trans fatty acids 0.5 392
14 vegetables 360 392
15 whole grains 125 392
# A tibble: 15 x 3
food optimal n
<chr> <dbl> <int>
1 calcium 1.25 5880
2 fiber 24 5880
3 fruits 250 5880
4 legumes 60 5880
5 milk 435 5880
6 nuts and seeds 21 5880
7 polyunsaturated fatty acids 11 5880
8 processed meat 2 5880
9 red meat 23 5880
10 seafood omega-3 fatty acids 0.25 5880
11 sodium 3 5880
12 sugar-sweetened beverages 3 5880
13 trans fatty acids 0.5 5880
14 vegetables 360 5880
15 whole grains 125 5880
# A tibble: 15 x 6
direction food lower_optimal optimal upper_optimal unit_optimal
<chr> <chr> <dbl> <dbl> <dbl> <chr>
1 low fruits 200 250 300 g
2 low vegetables 290 360 430 g
3 low legumes 50 60 70 g
4 low whole grains 100 125 150 g
5 low nuts and see… 16 21 25 g
6 low milk 350 435 520 g
7 high red meat 18 23 27 g
8 high processed me… 0 2 4 g
9 high sugar-sweete… 0 3 5 g
10 low fiber 19 24 28 g
11 low calcium 1 1.25 1.5 g
12 low seafood omeg… 0.2 0.25 0.3 g
13 low polyunsatura… 9 11 13 %
14 high trans fatty … 0 0.5 1 %
15 high sodium 1 3 5 g
Looks good!
Calculate relative consumption
Again, we would like to compare the consumption rates of this dietary factors by different groups of people, but ideally we want to know this relative to the optimal guidelines.
Thus lets calcuate values of consuption that are relative to the suggested guidelines.
There are a few ways we could do this. One is to calculate a percentage of consumption based on the mean value for each observed value relative to the optimal value. To do this we will use the mutate() function of the dplyrpackage. This will create a new variable called mean_percent that will be equal to the division result of the mean variable value and the optimal variable multiplied by 100 to create a percentage.
Another option is to incorperate the range of optimal intakes and the direction that is associated with health risk. If the direction of risk is high and the consumption was greater than the optimal mean value, than the percentage is calculated based on the upper_optimal value, while if the direction of risk is low and the consumption is less than the optimal mean value, then the percentage is calculated based on the lower_optimal value. We will use the case_when() function of the dplyr package to do this. This allows us to specify values (indicated on the right side of the ~symbol) based on specific conditions (indicated on the left side of the ~ symbol). We can specify multiple conditions using the & symbol.
Yet another option is to create a binary outcome of if optimal consumption was achieved or not.
Observations: 5,880
Variables: 20
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 201…
$ location_name <chr> "Global", "Global", "Global", "Global", "Glob…
$ rei_id <dbl> 111, 111, 112, 112, 113, 113, 114, 114, 115, …
$ food <chr> "fruits", "fruits", "vegetables", "vegetables…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "…
$ sex <chr> "Male", "Female", "Male", "Female", "Male", "…
$ parameter <chr> "continuous", "continuous", "continuous", "co…
$ mean <dbl> 8.703202e+01, 9.953182e+01, 1.975187e+02, 1.8…
$ upper <dbl> 8.988734e+01, 1.023450e+02, 2.083679e+02, 1.9…
$ lower <dbl> 8.452347e+01, 9.672140e+01, 1.887154e+02, 1.7…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", …
$ direction <chr> "low", "low", "low", "low", "low", "low", "lo…
$ lower_optimal <dbl> 200.0, 200.0, 290.0, 290.0, 100.0, 100.0, 16.…
$ optimal <dbl> 250.00, 250.00, 360.00, 360.00, 125.00, 125.0…
$ upper_optimal <dbl> 300.0, 300.0, 430.0, 430.0, 150.0, 150.0, 25.…
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", …
$ mean_percent <dbl> 34.8128083, 39.8127275, 54.8663179, 50.898279…
$ range_percent <dbl> 43.5160103, 49.7659094, 68.1099118, 63.184071…
$ percent_over_under <dbl> 56.483990, 50.234091, 31.890088, 36.815929, 7…
$ opt_achieved <chr> "No", "No", "No", "No", "No", "No", "No", "No…
Observations: 88,200
Variables: 20
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 201…
$ location_name <chr> "Global", "Global", "Global", "Global", "Glob…
$ food <chr> "fruits", "fruits", "fruits", "fruits", "frui…
$ age_group_id <dbl> 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 3…
$ age_group_name <chr> "25 to 29", "30 to 34", "35 to 39", "40 to 44…
$ sex <chr> "Male", "Male", "Male", "Male", "Male", "Male…
$ parameter <chr> "continuous", "continuous", "continuous", "co…
$ mean <dbl> 68.54567, 72.62209, 76.73157, 81.03910, 88.79…
$ upper <dbl> 75.16806, 80.00433, 84.73205, 89.52747, 100.9…
$ lower <dbl> 63.17081, 66.78018, 71.04691, 73.82734, 80.40…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", …
$ direction <chr> "low", "low", "low", "low", "low", "low", "lo…
$ lower_optimal <dbl> 200, 200, 200, 200, 200, 200, 200, 200, 200, …
$ optimal <dbl> 250, 250, 250, 250, 250, 250, 250, 250, 250, …
$ upper_optimal <dbl> 300, 300, 300, 300, 300, 300, 300, 300, 300, …
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", …
$ mean_percent <dbl> 27.41827, 29.04883, 30.69263, 32.41564, 35.51…
$ range_percent <dbl> 34.27284, 36.31104, 38.36578, 40.51955, 44.39…
$ percent_over_under <dbl> 65.72716, 63.68896, 61.63422, 59.48045, 55.60…
$ opt_achieved <chr> "No", "No", "No", "No", "No", "No", "No", "No…
One last thing that can be useful with data wrangling is to reshape the data into what is called the long format. This is very useful for creating visualizations with a very useful package called ggplot2.
To coerce an object into long format, we create more rows and fewer columns. For a more information about this, please see this case study.
We would like to put toether the different types of percentages of the optimal intake that we just calculated.
To get our data in long format we can use the pivot_longer() function of the dplyr package. We will also show how this would be done with the older version of this function, called gather().
For pivot_longer(), we will list the columns that we want to come together into the longer format using the cols argument. For gather() we would simply list the variables that we wish to consolidate. The names_to argument indicates the name of the variable that will include the character information about the values that we are consolidating, this is the variable names of the columns that we are bringing together. This is equivalent to the key aregument in gather(). The values_to is the name of the column that will contain the values of teh columns we are consolidating. This is equivalent to the value aregument in gather(). We can use contains() of the tidyr package to look at the variables with names that contain "percent" .
We would get an identical output from the methods.
[1] TRUE
Let’s do the same for the age separated data.
Data Exploration
Exploring age collapsed data
Let’s take a look at the percent of consumption. Again we will use the base R summary() function:
mean_percent
Min. : 0.02
1st Qu.: 11.20
Median : 34.71
Mean : 187.86
3rd Qu.: 73.12
Max. :7693.68
Wow! Some of the values are nearly zero, suggesting that some people are consuming basically zero percent of what is suggested for optimal health. On the other hand, for some dietary factors people are consuming over 7,000 percent what is suggested!
This is why it is important to look at the direction of consumption that could be harmful. For example if there is a population that consumes large amounts of vegatables this could be a good thing, but if there is a population consuming large amounts of sodium this would be a bad thing.
Let’s take a look to see what dietary factors are at the extremes by arranging the data using the arrange() function of the dplyr package. We can arrange by smallest to largest using the default and we can arrange largest to smallest using the minus sign -.
Observations: 5,880
Variables: 20
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 201…
$ location_name <chr> "Costa Rica", "Colombia", "Panama", "Venezuel…
$ rei_id <dbl> 118, 118, 118, 118, 118, 118, 118, 118, 118, …
$ food <chr> "sugar-sweetened beverages", "sugar-sweetened…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "…
$ sex <chr> "Male", "Male", "Male", "Male", "Male", "Male…
$ parameter <chr> "continuous", "continuous", "continuous", "co…
$ mean <dbl> 230.8105, 201.7180, 194.4116, 193.9048, 188.4…
$ upper <dbl> 247.9342, 216.9260, 208.8040, 208.8702, 203.3…
$ lower <dbl> 215.5919, 189.4812, 181.7150, 180.7209, 174.5…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", …
$ direction <chr> "high", "high", "high", "high", "high", "high…
$ lower_optimal <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ optimal <dbl> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, …
$ upper_optimal <dbl> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, …
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", …
$ mean_percent <dbl> 7693.684, 6723.934, 6480.386, 6463.492, 6282.…
$ range_percent <dbl> 4616.211, 4034.361, 3888.232, 3878.095, 3769.…
$ percent_over_under <dbl> 4516.211, 3934.361, 3788.232, 3778.095, 3669.…
$ opt_achieved <chr> "No", "No", "No", "No", "No", "No", "No", "No…
Ok, so it looks like sugar-sweetened beverages are really overconsumed in some parts of the world!
Recall from the supplementary table from the article that overconsumption of sugar-sweetened beverages is associated with both Diabetes mellitus type 2 and Ischemic heart disease. This article discusses some of the contrevsy over the potential health risks associated with high consumption of sugar.
It still looks quite bad if we look at the other calculated percentage values.
mean_percent range_percent percent_over_under
Min. : 0.02 Min. : 0.025 Min. : 0.00
1st Qu.: 11.20 1st Qu.: 13.263 1st Qu.: 0.00
Median : 34.71 Median : 38.941 Median : 56.82
Mean : 187.86 Mean : 127.272 Mean : 122.91
3rd Qu.: 73.12 3rd Qu.: 72.414 3rd Qu.: 87.78
Max. :7693.68 Max. :4616.211 Max. :4516.21
So some places are still consuming 4,000 percent more than the upper range of the suggested optimal intake.
Let’s take a look at global levels:
# A tibble: 2 x 20
year_id location_name rei_id food age_group_name sex parameter mean
<dbl> <chr> <dbl> <chr> <chr> <chr> <chr> <dbl>
1 2017 Global 118 suga… All Available… Male continuo… 65.5
2 2017 Global 118 suga… All Available… Fema… continuo… 47.7
# … with 12 more variables: upper <dbl>, lower <dbl>, unit <chr>,
# direction <chr>, lower_optimal <dbl>, optimal <dbl>,
# upper_optimal <dbl>, unit_optimal <chr>, mean_percent <dbl>,
# range_percent <dbl>, percent_over_under <dbl>, opt_achieved <chr>
For those who are less familiar with the metric system where grams are equivalent to milliliters, it may be useful to realize how many fluid ounces the max amount of consumption per day (~248) grams actaully is.
There are 0.35247 ounces in one gram.
[1] 87.38937
Ok, so the top consumers are drinking about 87 fluid ounces per day. Since there are 12 ounces in a single can of soda, this is about 7.25 sodas per day. Globally on average, males are drinking 1.9238988 about sodas worth of sweetened beverages, while females are drinking about 1.4010682.
Let’s take a look at what is underconsumed:
Observations: 5,880
Variables: 20
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 201…
$ location_name <chr> "Chad", "Chad", "Mali", "Mali", "Burkina Faso…
$ rei_id <dbl> 122, 122, 122, 122, 122, 122, 122, 122, 122, …
$ food <chr> "polyunsaturated fatty acids", "polyunsaturat…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "…
$ sex <chr> "Female", "Male", "Female", "Male", "Female",…
$ parameter <chr> "continuous", "continuous", "continuous", "co…
$ mean <dbl> 0.002227074, 0.002295916, 0.002301266, 0.0023…
$ upper <dbl> 0.002383410, 0.002439931, 0.002461209, 0.0025…
$ lower <dbl> 0.002082132, 0.002161922, 0.002152212, 0.0022…
$ unit <chr> "%energy/day", "%energy/day", "%energy/day", …
$ direction <chr> "low", "low", "low", "low", "low", "low", "lo…
$ lower_optimal <dbl> 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, …
$ optimal <dbl> 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 1…
$ upper_optimal <dbl> 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1…
$ unit_optimal <chr> "%", "%", "%", "%", "%", "%", "%", "%", "%", …
$ mean_percent <dbl> 0.02024613, 0.02087196, 0.02092060, 0.0215757…
$ range_percent <dbl> 0.02474527, 0.02551018, 0.02556962, 0.0263703…
$ percent_over_under <dbl> 99.97525, 99.97449, 99.97443, 99.97363, 99.96…
$ opt_achieved <chr> "No", "No", "No", "No", "No", "No", "No", "No…
On the otherhand, it looks like some places are consuming almost no polyunsaturated fatty acids. These are fats that found in plant-based sources like seeds and nuts. According to an article about polyunsaturated fatty acids and its influence on health:
Coronary heart disease (CHD) is the leading cause of death worldwide … The types of dietary fats consumed play an important role in CHD risk, representing key modifiable risk factors…In particular, higher intakes of trans fat (TFA) and of saturated fat (SFA) replacing ω‐6 (n‐6) polyunsaturated fat (PUFA) are associated with increased CHD… whereas higher intake of PUFA replacing either SFA or carbohydrate is associated with lower risk.
Let’s get an idea about how countries compare in terms of how many of the dietary factors are consumed at the optimal level (the opt_achieved variable).
# A tibble: 2 x 2
opt_achieved n
<chr> <int>
1 No 4360
2 Yes 1520
Looks like overal, only 34.8623853 of dietary factors for all tested populations were at optimal levels.
Let’s get an idea about how countries compare.
Looks as though on average the populations (both male and female separately) in Qatar, Rwanda, and Turkey consumped the optimal level of intake for the largest number of dietary factors (13 out of 30 (for the 15 dietary factors for males and females)).
In contrast, the Czech Republic, Greenland, Hungary, Slovakia, Slovenia, and the United States had the poorest consumption rates (27 out of 30 were not at optimal levels).
Let’s look at the raw US data:
Observations: 30
Variables: 20
$ year_id <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 201…
$ location_name <chr> "United States", "United States", "United Sta…
$ rei_id <dbl> 111, 111, 112, 112, 113, 113, 114, 114, 115, …
$ food <chr> "fruits", "fruits", "vegetables", "vegetables…
$ age_group_name <chr> "All Available Ages", "All Available Ages", "…
$ sex <chr> "Male", "Female", "Male", "Female", "Male", "…
$ parameter <chr> "continuous", "continuous", "continuous", "co…
$ mean <dbl> 114.24773940, 129.11513300, 208.93230110, 192…
$ upper <dbl> 121.37292480, 136.94611510, 217.80223830, 200…
$ lower <dbl> 107.89222320, 122.33941970, 200.05582000, 184…
$ unit <chr> "g/day", "g/day", "g/day", "g/day", "g/day", …
$ direction <chr> "low", "low", "low", "low", "low", "low", "lo…
$ lower_optimal <dbl> 200.0, 200.0, 290.0, 290.0, 100.0, 100.0, 16.…
$ optimal <dbl> 250.00, 250.00, 360.00, 360.00, 125.00, 125.0…
$ upper_optimal <dbl> 300.0, 300.0, 430.0, 430.0, 150.0, 150.0, 25.…
$ unit_optimal <chr> "g", "g", "g", "g", "g", "g", "g", "g", "g", …
$ mean_percent <dbl> 45.699096, 51.646053, 58.036750, 53.515649, 2…
$ range_percent <dbl> 57.123870, 64.557566, 72.045621, 66.433220, 2…
$ percent_over_under <dbl> 42.876130, 35.442434, 27.954379, 33.566780, 7…
$ opt_achieved <chr> "No", "No", "No", "No", "No", "No", "No", "No…
Let’s see how males and females compare for achieving the optimal intake:
# A tibble: 4 x 3
sex opt_achieved n
<chr> <chr> <int>
1 Female No 2171
2 Female Yes 769
3 Male No 2189
4 Male Yes 751
Looks pretty similar, but it may be a bit better for females. We will evaluate this further.
Here is a way we can visualise this with the ggplot2 package. The ggplot2 package creates plots by using layers. Notice in the following code how there is a plus sign between the ggplot() function and the geom_histogram() function. With ggplot2 we select what data we would like to plot using the first function (ggplot()) and then we add on additional layers of complexity (these layers can even involve different data). The aes() argument specifies what aspects of the data will be plotted where. the geom_* function specifies what type of plot to create (e.g. geom_histogram() create a histogram).
We will see later how we can add many layers to plots with ggplot2. For additional information on using ggplot2, see this case study.
Continuing with ggplot2 we will now create a different plot - this time we will create a series of boxplots. We will use the facet_wrap() function of ggplot2 to allow us to create many different plots simultaneously. In this case we can look at boxplots for the different dietary factors colored by sex. The scales argument when set to "free" means that each of the sequentual plot created by the facet can have a differnt scale for the y axis, otherwise, by default they are constrained to the same scale.
diet_and_guidelines%<>%
mutate(food_to_plot =
str_replace(
string =pull(diet_and_guidelines,food),
pattern = " ",
replacement = "\n"))
diet_and_guidelines %>%
ggplot(aes(y = mean_percent , x= sex, color = sex))+
geom_boxplot()+
facet_wrap(~food_to_plot, scales = "free", nrow = 3, strip.position = "right")+
theme(strip.text.y = element_text(size = 8),
axis.text.x = element_text(angle = 70, hjust = 1))

If we just look at differences by sex for the specific dietary factors, males appear to potentially consume more of many of the factors, including possibly more sodium, fiber, calcium, red meat, and sugar-sweetened beverages than females. Females may consume more fruit.
Exploring the data separated by age
Now we will take a look at the data that is separated by age groups.
First, recall that we have 15 different age groups starting from age 25 to 95 plus.
# A tibble: 15 x 2
age_group_name n
<chr> <int>
1 25 to 29 5880
2 30 to 34 5880
3 35 to 39 5880
4 40 to 44 5880
5 45 to 49 5880
6 50 to 54 5880
7 55 to 59 5880
8 60 to 64 5880
9 65 to 69 5880
10 70 to 74 5880
11 75 to 79 5880
12 80 to 84 5880
13 85 to 89 5880
14 90 to 94 5880
15 95 plus 5880

We can see from these plots that there appears to be age differences and gender differences for some of the different dietary factors. We will work to create clearer figures later on. However these figures have given us a better sense of the data that we are working with.
LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXMgOiBFeHBsb3JpbmcgZ2xvYmFsIHBhdHRlcm5zIG9mIGRpZXRhcnkgYmVoYXZpb3JzIGFzc29jaWF0ZWQgd2l0aCBoZWFsdGggcmlzayAiCmNzczogc3R5bGUuY3NzCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgc2VsZl9jb250YWluZWQ6IHllcwogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgb3V0LndpZHRoID0gJzkwJScpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShrbml0cikKYGBgCgoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIGV2YWwgPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIm1haW5wbG90LnBuZyIpKQpgYGAKCiMjIHsuZGlzY2xhaW1lcl9ibG9ja30KCioqRGlzY2xhaW1lcioqOiBUaGUgcHVycG9zZSBvZiB0aGUgW09wZW4gQ2FzZSBTdHVkaWVzXShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8pe3RhcmdldD0iX2JsYW5rIn0gcHJvamVjdCBpcyAqKnRvIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgdmFyaW91cyBkYXRhIHNjaWVuY2UgbWV0aG9kcywgdG9vbHMsIGFuZCBzb2Z0d2FyZSBpbiB0aGUgY29udGV4dCBvZiBtZXNzeSwgcmVhbC13b3JsZCBkYXRhKiouIEEgZ2l2ZW4gY2FzZSBzdHVkeSBkb2VzIG5vdCBjb3ZlciBhbGwgYXNwZWN0cyBvZiB0aGUgcmVzZWFyY2ggcHJvY2VzcywgaXMgbm90IGNsYWltaW5nIHRvIGJlIHRoZSBtb3N0IGFwcHJvcHJpYXRlIHdheSB0byBhbmFseXplIGEgZ2l2ZW4gZGF0YXNldCwgYW5kIHNob3VsZCBub3QgYmUgdXNlZCBpbiB0aGUgY29udGV4dCBvZiBtYWtpbmcgcG9saWN5IGRlY2lzaW9ucyB3aXRob3V0IGV4dGVybmFsIGNvbnN1bHRhdGlvbiBmcm9tIHNjaWVudGlmaWMgZXhwZXJ0cy4gCgojIyBNb3RpdmF0aW9uCkFuIFthcnRpY2xlXShodHRwczovL3d3dy50aGVsYW5jZXQuY29tL2FjdGlvbi9zaG93UGRmP3BpaT1TMDE0MC02NzM2JTI4MTklMjkzMDA0MS04KXt0YXJnZXQ9Il9ibGFuayJ9IHdhcyByZWNlbnRseSBwdWJsaXNoZWQgaW4gdGhlIGxhbmNldCBqb3VybmFsIHRoYXQgZXZhbHVhdGVzIGdsb2JhbCBkaWV0YXJ5IHRyZW5kcyBhbmQgdGhlIHJlbGF0aW9uc2hpcCBvZiB0aGVzZSBkaWV0YXJ5IGZhY3RvcnMgd2l0aCBtb3J0YWxpdHkgYW5kIGZlcnRpbGl0eS4KCmBgYHtyLCBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJ0aGVwYXBlci5wbmciKSkKYGBgCgojIyMjIHsucmVmZXJlbmNlX2Jsb2NrfQpHQkQgMjAxNyBEaWV0IENvbGxhYm9yYXRvcnMuIEhlYWx0aCBlZmZlY3RzIG9mIGRpZXRhcnkgcmlza3MgaW4gMTk1IGNvdW50cmllcywgMTk5MOKAkzIwMTc6IGEgc3lzdGVtYXRpYyBhbmFseXNpcyBmb3IgdGhlIEdsb2JhbCBCdXJkZW4gb2YgRGlzZWFzZSBTdHVkeSAyMDE3LiAqVGhlIExhbmNldCogMzkzLCAxOTU44oCTMTk3MiAoMjAxOSkuCgojIyMjCgpUaGlzIGFydGljbGUgZXZhbHVhdGVkIGZvb2QgY29uc3VtcHRpb24gcGF0dGVybnMgaW4gMTk1IGNvdW50cmllcyBmb3IgMTUgZGlmZmVyZW50IGRpZXRhcnkgcmlzayBmYWN0b3JzIHRoYXQgaGF2ZSBwcm9iYWJsZSBhc3NvY2lhdGlvbnMgd2l0aCBub24tY29tbXVuaWNhYmxlIGRpc2Vhc2UgKE5DRCkuIEZvciBleGFtcGxlLCBvdmVyY29uc3VtcHRpb24gb2Ygc29kaXVtIGlzIGFzc29jaWF0ZWQgd2l0aCBoaWdoIGJsb29kIHByZXNzdXJlLiBUaGVzZSBjb25zdW1wdGlvbiBsZXZlbHMgd2VyZSB0aGVuIHVzZWQgdG8gZXN0aW1hdGUgbGV2ZWxzIG9mIG1vcnRhbGl0eSBhbmQgbW9yYmlkaXR5IGR1ZSBOQ0QsIGFzIHdlbGwgYXMgZGlzYWJpbGl0eS1hZGp1c3RlZCBsaWZlLXllYXJzIChEQUxZcykgYXR0cmlidXRpYmxlIHRvIHN1Ym9wdGltYWwgY29uc3VtcHRpb24gb2YgZm9vZHMgcmVsYXRlZCB0byB0aGVzZSBkaWV0YXJ5IHJpc2sgZmFjdG9ycy4gVGhlIGF1dGhvcnMgZm91bmQgdGhhdDogCgo+ICJIaWdoIGludGFrZSBvZiBzb2RpdW0gLi4uLCBsb3cgaW50YWtlIG9mIHdob2xlIGdyYWlucyAuLi4sIGFuZCBsb3cgaW50YWtlIG9mIGZydWl0cyAuLi4gd2VyZSB0aGUgbGVhZGluZyBkaWV0YXJ5IHJpc2sgZmFjdG9ycyBmb3IgZGVhdGhzIGFuZCBEQUxZcyBnbG9iYWxseSBhbmQgaW4gbWFueSBjb3VudHJpZXMuIiAKClRoaXMgZmlndXJlIGZyb20gdGhlIHN1cHBsZW1lbnQgc2hvd3MgdGhlIHJhbmtpbmcgb2YgdGhlIDE1IGRpZXRhcnkgcmlzayBmYWN0b3JzIGJhc2VkIG9uIHRoZSBlc3RpbWF0ZWQgbnVtYmVyIG9mIGF0dHJpYnV0YWJsZSBkZWF0aHMgYW5kIGlsbHVzdGFydGVzIGhvdyB0aGUgdG9wIDMgcmlzayBmYWN0b3JzIGFyZSBvZnRlbiBpc3N1ZXMgZm9yIG1hbnkgZGlmZmVyZW50IGNvdW50cmllcy4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0gIjcwMCBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJkZWF0aHMucG5nIikpCmBgYAoKVGhpcyBjYXNlIHN0dWR5IHdpbGwgZXZhbHVhdGUgdGhlIGRhdGEgcmVwb3J0ZWQgaW4gdGhpcyBhcnRpY2xlIHRvIGV4cGxvcmUgcmVnaW9uYWwsIGFnZSwgYW5kIGdlbmRlciBzcGVjaWZpYyBkaWZmZXJlbmNlcyBpbiBkaWV0YXJ5IGNvbnN1bXB0aW9uIHBhdHRlcm5zIGFyb3VuZCB0aGUgd29ybGQgaW4gMjAxNy4gCgojIyMgTWFpbiBRdWVzdGlvbnMKCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gT3VyIG1haW4gcXVlc3Rpb25zIGFyZTogPC91PjwvYj4KCjEpIFdoYXQgYXJlIHRoZSBnbG9iYWwgdHJlbmRzIGZvciBwb3RlbnRpYWxseSBoYXJtZnVsIGRpZXRzPwoyKSBIb3cgZG8gbWFsZXMgYW5kIGZlbWFsZXMgY29tcGFyZT8KMykgSG93IGRvIGRpZmZlcmVudCBhZ2UgZ3JvdXBzIGNvbXBhcmUgZm9yIHRoZXNlIGRpZXRhcnkgZmFjdG9ycz8KNCkgSG93IGRvIGRpZmZlcmVudCBjb3VudHJpZXMgY29tcGFyZT8gSW4gcGFydGljdWxhciwgaG93IGRvZXMgdGhlIFVTIGNvbXBhcmUgdG8gb3RoZXIgY29udHJpZXMgaW4gdGVybXMgb2YgZGlldCB0cmVuZHM/CgojIyMjCgojIyMgTGVhcm5pbmcgT2JqZWN0aXZlcyAKCkluIHRoaXMgY2FzZSBzdHVkeSwgd2XigJlsbCB3YWxrIHlvdSB0aHJvdWdoIGltcG9ydGluZyBkYXRhIGZyb20gYSBwZGYsIGNsZWFuaW5nIGRhdGEsIHdyYW5nbGluZyBkYXRhLCB2aXN1YWxpemluZyB0aGUgZGF0YSwgYW5kIDxiPiBjb21wYXJpbmcgdHdvIG9yIG1vcmUgZ3JvdXBzIDwvYj4gdXNpbmcgd2VsbC1lc3RhYmxpc2hlZCBhbmQgY29tbW9ubHkgdXNlZCBwYWNrYWdlcywgaW5jbHVkaW5nIGBzdHJpbmdyYCwgYHRpZHlyYCwgYGRwbHlyYCwgYHB1cnJyYCwgYW5kIGBnZ3Bsb3QyYC4gV2Ugd2lsbCBlc3BlY2lhbGx5IGZvY3VzIG9uIHVzaW5nIHBhY2thZ2VzIGFuZCBmdW5jdGlvbnMgZnJvbSB0aGUgW1RpZHl2ZXJzZV0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0uIFRoZSBUaWR5dmVyc2UgaXMgYSBsaWJyYXJ5IG9mIHBhY2thZ2VzIGNyZWF0ZWQgYnkgdGhlIGNoaWVmIHNjaWVudGlzdCBhdCBSU3R1ZGlvLCBIYWRsZXkgV2lja2hhbS4gV2hpbGUgc29tZSBzdHVkZW50cyBtYXkgYmUgZmFtaWxpYXIgd2l0aCBwcmV2aW91cyBSIHByb2dyYW1taW5nIHBhY2thZ2VzLCB0aGVzZSBwYWNrYWdlcyBtYWtlIGRhdGEgc2NpZW5jZSBpbiBSIGVzcGVjaWFsbHkgZWZmaWNpZW50LgoKCgpgYGB7ciwgb3V0LndpZHRoID0gIjIwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly90aWR5dmVyc2UudGlkeXZlcnNlLm9yZy9sb2dvLnBuZyIpCmBgYAoKCgpXZSB3aWxsIGJlZ2luIGJ5IGxvYWRpbmcgdGhlIHBhY2thZ2VzIHRoYXQgd2Ugd2lsbCBuZWVkOgoKYGBge3J9CmxpYnJhcnkoaGVyZSkKbGlicmFyeShyZWFkcikKbGlicmFyeShkcGx5cikKbGlicmFyeShza2ltcikKbGlicmFyeShwZGZ0b29scykKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KHB1cnJyKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeSh0aWR5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShmb3JjYXRzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoY293cGxvdCkKYGBgCgoKIFBhY2thZ2UgICB8IFVzZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YQpbcmVhZHJdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGltcG9ydCB0aGUgY3N2IGZpbGUgZGF0YQpbZHBseXJdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGFycmFuZ2UvZmlsdGVyL3NlbGVjdC9jb21wYXJlIHNwZWNpZmljIHN1YnNldHMgb2YgdGhlIGRhdGEgCltza2ltcl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3NraW1yL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGdldCBhbiBvdmVydmlldyBvZiBkYXRhCltwZGZ0b29sc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3BkZnRvb2xzL3BkZnRvb2xzLnBkZil7dGFyZ2V0PSJfYmxhbmsifSAgIHwgdG8gcmVhZCBhIHBkZiBpbnRvIFIgICAKW3N0cmluZ3JdKGh0dHBzOi8vc3RyaW5nci50aWR5dmVyc2Uub3JnL2FydGljbGVzL3N0cmluZ3IuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIG1hbmlwdWxhdGUgdGhlIHRleHQgd2l0aGluIHRoZSBwZGYgb2YgdGhlIGRhdGEKW21hZ3JpdHRyXShodHRwczovL21hZ3JpdHRyLnRpZHl2ZXJzZS5vcmcvYXJ0aWNsZXMvbWFncml0dHIuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgIHwgdG8gdXNlIHRoZSBgJTw+JWAgcGlwcGluZyBvcGVyYXRvcgpbcHVycnJdKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHBlcmZvcm0gZnVuY3Rpb25zIG9uIGFsbCBjb2x1bW5zIG9mIGEgdGliYmxlClt0aWJibGVdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICB8IHRvIGNyZWF0ZSBkYXRhIG9iamVjdHMgdGhhdCB3ZSBjYW4gbWFuaXB1bGF0ZSB3aXRoIGRwbHlyL3N0cmluZ3IvdGlkeXIvcHVycnIKW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBzZXBhcmF0ZSBkYXRhIHdpdGhpbiBhIGNvbHVtbiBpbnRvIG11bHRpcGxlIGNvbHVtbnMKW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIG1ha2UgdmlzdWFsaXphdGlvbnMgd2l0aCBtdWx0aXBsZSBsYXllcnMKW2dncHVicl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dncHVici9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gZWFzaWx5IGFkZCByZWdyZXNzaW9uIGxpbmUgZXF1YXRpb25zIHRvIHBsb3RzCltmb3JjYXRzXShodHRwczovL2ZvcmNhdHMudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBjaGFuZ2UgZGV0YWlscyBhYm91dCBmYWN0b3JzIChjYXRlZ29yaWNhbCB2YXJpYWJsZXMpCltnZ3JlcGVsXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2dyZXBlbC92aWduZXR0ZXMvZ2dyZXBlbC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gYWxsb3cgbGFiZWxzIGluIGZpZ3VyZXMgbm90IHRvIG92ZXJsYXAKW2Nvd3Bsb3RdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9jb3dwbG90L3ZpZ25ldHRlcy9pbnRyb2R1Y3Rpb24uaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIGFsbG93IHBsb3RzIHRvIGJlIGNvbWJpbmVkCl9fXwoKCltnbHVlXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnL2Jsb2cvMjAxNy8xMC9nbHVlLTEuMi4wLyl7dGFyZ2V0PSJfYmxhbmsifSAgfCB0byBwYXN0ZSBvciBjb21iaW5lIGNoYXJhY3RlciBzdHJpbmdzIGFuZCBkYXRhIHRvZ2V0aGVyCgoKVGhlIGZpcnN0IHRpbWUgd2UgdXNlIGEgZnVuY3Rpb24sIHdlIHdpbGwgdXNlIHRoZSBgOjpgIHRvIGluZGljYXRlIHdoaWNoIHBhY2thZ2Ugd2UgYXJlIHVzaW5nLiBVbmxlc3Mgd2UgaGF2ZSBvdmVybGFwcGluZyBmdW5jdGlvbiBuYW1lcywgdGhpcyBpcyBub3QgbmVjZXNzYXJ5LCBidXQgd2Ugd2lsbCBpbmNsdWRlIGl0IGhlcmUgdG8gYmUgaW5mb3JtYXRpdmUgYWJvdXQgd2hlcmUgdGhlIGZ1bmN0aW9ucyB3ZSB3aWxsIHVzZSBjb21lIGZyb20uCgoKIyMjIENvbnRleHQKCkhlcmUgaXMgYW4gZXhjZXJwdCBmcm9tIHRoZSBhcnRpY2xlIGl0c2VsZiBhYm91dCB0aGUgY29udGV4dCBvZiB0aGUgd29yazoKYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgImNvbnRleHQucG5nIikpCmBgYAoKTWFueSBkaWV0YXJ5IGZhY3RvcnMgaGF2ZSB3ZWxsLWVzdGFiaXNoZWQgYXNzb2NpYXRpb25zIHdpdGggaGVhbHRoIHJpc2suIFRoZSBhdXRob3JzIHRoYXQgZ2VuZXJhdGVkIHRoaXMgZGF0YXNldCBpZGVudGlmaWVkIDE1IGRpZXRhcnkgZmFjdG9ycyB0aGF0IGhhdmUgcHJvYmFibHkgaGVhbHRoIHJpc2sgYmFzZWQgb24gbGl0ZXJhdHVyZSBzZWFyY2guCgpIZXJlIHlvdSBjYW4gc2VlIGEgdGFibGUgb2YgdGhlIHNvdXJjZXMgZm9yIHRoZSBoZWFsdGggcmlza3MgYXNzb2NpYXRlZCB3aXRoIHRoZSBkaWV0YXJ5IGZhY3RvcnMuIFJDVCBzdGFuZHMgZm9yIHJhbmRvbWl6ZWQgY29udHJvbCB0cmlhbHMuCgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSAiNzAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgImRpZXRhcnlyaXNrLnBuZyIpKQpgYGAKCgpJbiB0aGUgYXJ0aWNsZSB0aGUgYXV0aG9ycyBmb3VuZCB0aGF0IG1vc3Qgb2YgdGhlIG1vcnRhbGl0eSBhc3NvY2lhdGVkIHdpdGggZWFjaCBmYWN0b3IgaXMgcmVsYXRlZCB0byBjYXJkaW92YXNjdWxhciBkaXNlYXNlLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSAiNTAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgImNhcmRpb3Jpc2sucG5nIikpCmBgYAoKIyMjIExpbWl0YXRpb25zCgpUaGVyZSBhcmUgc29tZSBpbXBvcnRhbnQgbGltaXRhdGlvbnMgcmVnYXJkaW5nIHRoZSBkYXRhIGZyb20gdGhpcyBhcnRpY2xlIHRvIGtlZXAgaW4gbWluZC4gIFRoZSBkZWZpbml0aW9uIG9mIGNlcnRhaW4gZGlldGFyeSBmYWN0b3JzIHZhcmllZCBhY3Jvc3Mgc29tZSBvZiB0aGUgY29sbGVjdGlvbiBzb3VyY2VzLiBJbnRha2VzIG9mIGNlcnRhaW4gaGVhbHRoeSBmb29kcyBsaWtlIHZlZ2l0YWJsZXMgYW5kIGZydWl0cyBhcmUgbGlrZWx5IHBvc2l0aXZlbHkgY29ycmVsYXRlZCBhbmQgbGlrZWx5IG5lZ2F0aXZlbHkgY29ycmVsYXRlZCB3aXRoIGludGFrZXMgb2YgdW5oZWFsdGh5IGZvb2RzLiBNdWNoIG9mIHRoZSBkYXRhIHdhcyBjb2xsZWN0ZWQgd2l0aCAyNCBob3VyIHJlY2FsbCBzdXJ2ZXlzIHdoaWNoIGFyZSBwcm9uZSB0byBpc3N1ZXMgZHVlIHRvIGluYWNjdXJhY3kgb2YgbWVtb3J5IHJlY2FsbCBvciBvdGhlciBiaWFzZXMgc3VjaCBhcyBhIHRlbmRlbmN5IGZvciBzb21lIHBlb3BsZSB0byByZXBvcnQgaGVhbHRoaWVyIGJlaGF2aXJpb3JzLiBUaGUgZ3VpZGVsaW5lcyBpbiB0aGUgdGFibGUgYXJlIGJhc2VkIGFyZSBub3QgcGFyc2VkIGJ5IGdlbmRlciBldmVuIHRob3VnaCBpdCBpcyBrbm93biB0aGF0IHRoZXJlIGFyZSBkaWZmZXJlbnQgZGlldGFyeSByZXF1aXJlbWVudHMgZm9yIG9wdGltYWwgaGVhbHRoIGZvciBjZXJ0YWluIG51dHJpZW50cy4gVGhlIGFydGljbGUgZGlzY3Vzc2VzIHNvbWUgbGltaXRhdGlvbnMgYWJvdXQgYWNjb3VudGluZyBmb3Igb3ZlcmFsbCBmb29kIGNvbnN1bXB0aW9uIHdoZW4gY2FsY3VsdGluZyBjb25zdW1wdGlvbiBvZiBwYXJ0aWN1bGFyIGZvb2RzOgoKPiAiVG8gcmVtb3ZlIHRoZSBlZmZlY3Qgb2YgZW5lcmd5IGludGFrZSBhcyBhIHBvdGVudGlhbCBjb25mb3VuZGVyIGFuZCBhZGRyZXNzIG1lYXN1cmVtZW50IGVycm9yIGluIGRpZXRhcnkgYXNzZXNzbWVudCB0b29scywgbW9zdCBjb2hvcnRzIGhhdmUgYWRqdXN0ZWQgZm9yIHRvdGFsIGVuZXJneSBpbnRha2UgaW4gdGhlaXIgc3RhdGlzdGljYWwgbW9kZWxzLiBUaGlzIGVuZXJneSBhZGp1c3RtZW50IG1lYW5zIHRoYXQgZGlldCBjb21wb25lbnRzIGFyZSBkZWZpbmVkIGFzIHJpc2tzIGluIHRlcm1zIG9mIHRoZSBzaGFyZSBvZiBkaWV0IGFuZCBub3QgYXMgYWJzb2x1dGUgbGV2ZWxzIG9mIGV4cG9zdXJlLiBJbiBvdGhlciB3b3JkcywgYW4gaW5jcmVhc2UgaW4gaW50YWtlIG9mIGZvb2RzIGFuZCBtYWNyb251dHJpZW50cyBzaG91bGQgYmUgY29tcGVuc2F0ZWQgYnkgYSBkZWNyZWFzZSBpbiBpbnRha2Ugb2Ygb3RoZXIgZGlldGFyeSBmYWN0b3JzIHRvIGhvbGQgdG90YWwgZW5lcmd5IGludGFrZSBjb25zdGFudC4gVGh1cywgdGhlIHJlbGF0aXZlIHJpc2sgb2YgY2hhbmdlIGluIGVhY2ggY29tcG9uZW50IG9mIGRpZXQgZGVwZW5kcyBvbiB0aGUgb3RoZXIgY29tcG9uZW50cyBmb3Igd2hpY2ggaXQgaXMgc3Vic3RpdHV0ZWQuIEhvd2V2ZXIsIHRoZSByZWxhdGl2ZSByaXNrcyBlc3RpbWF0ZWQgZnJvbSBtZXRhLWFuYWx5c2VzIG9mIGNvaG9ydCBzdHVkaWVzIGRvIG5vdCBnZW5lcmFsbHkgc3BlY2lmeSB0aGUgdHlwZSBvZiBzdWJzdGl0dXRpb24uCgpUaGVyZSBhcmUgYWxzbyBpbXBvcnRhbnQgbnVhbmNlcyB0byBrZWVwIGluIG1pbmQgcmVncmFkaW5nIHNvbWUgb2YgdGhlIGRpZXRhcnkgZmFjdG9ycy4gRm9yIGV4YW1wbGUgY2FsY2l1bSBjb25zdW1wdGlvbiB3YXMgY2FsY3VsYXRlZCBiYXNlZCBvbiBjb25zdW1wdGlvbiBvZiBkYWlyeSBwcm9kdWN0cywgaG93ZXZlciBjYWxjaXVtIGNhbiBiZSBhcXVpcmVkIGZyb20gb3RoZXIgc291cmNlcyBpbmNsdWRpbmcgcGxhbnQtYmFzZWQgc291cmNlcy4gSG93ZXZlciBpbiB0aGVzZSBkYXRhLCB0aGUgaW5mbHVlbmNlIG9mIHBsYW50LWJhc2VkIGNvbnN1bXB0aW9uIG9mIGNhbGNpdW0gd2FzIGFsc28gbm90IGFjY291bnRlZCBmb3IsIG5vciB3YXMgc3VwcGxlbWVudGF0aW9uIHRocm91Z2ggdml0YW1pbiBzb3VyY2VzLiAKCiMjIFdoYXQgYXJlIHRoZSBkYXRhPwoKV2Ugd2lsbCBiZSB1c2luZyBkYXRhIHRoYXQgd2UgcmVxdWVzdGVkIGZyb20gdGhlIFtHQkRdKGh0dHA6Ly93d3cuaGVhbHRoZGF0YS5vcmcvZ2JkKXt0YXJnZXQ9Il9ibGFuayJ9IGFib3V0IGRpZXRhcnkgaW50YWtlLCBhcyB3ZWxsIGFzIHRoZSBndWlkZWxpbmUgZGF0YSBhYm91dCBvcHRpbWFsIGNvbnN1bXB0aW9uIGFtb3VudHMgZm9yIGRpZmZlcmVudCBmb29kcyBjb250YWluZWQgd2l0aGluIHRoZSBQREYgb2YgdGhlIGFydGljbGUuIFdlIGhhdmUgdHdvIGNzdiBmaWxlcy4gVGhlIGZpcnN0IG9uZSBpbmNsdWRlcyBjb25zdW1wdGlvbiBsZXZlbHMgYXQgdGhlIGdsb2JhbCBsZXZlbCBhbmQgZm9yIGRpZmZlcmVudCBjb3VudHJpZXMgZm9yIGFsbCBhZ2VzIGNvbWJpbmVkLgoKTG9va2luZyBhdCB0aGUgY3N2IGZpbGUgaW4gZXhjZWw6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjcwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwiY3N2LnBuZyIpKQpgYGAKCkhlcmUgeW91IGNhbiBzZWUgdGhhdCB0aGUgZGF0YSBjb250YWlucyBtZWFuIGNvbnN1bXB0aW9uIHZhbHVlcyBmb3IgYm90aCBtZW4gYW5kIHdvbWVuIGluIHZhcmlvdXMgY291bnRyaWVzIGF0IHRoZSBuYXRpb25hbCBsZXZlbCBpbiAyMDE3IGZvciB2YXJpb3VzIGZvb2RzIHRoYXQgbWF5IGJlIHByb2JsZW1hdGljIGZvciBoZWFsdGguIFRoZSB1bml0cyBmb3IgdGhlIGZvb2QgdmFyaWVzLiBTbyBmb3IgZXhhbXBsZSwgdGhlIG1lYW4gY29sdW1uIGluIHJvdyB0aGF0IHNheXMgIkRpZXQgbG93IGluIGZpYmVyIiBpbmRpY2F0ZXMgdGhlIGF2ZXJhZ2UgY29uc3VtcHRpb24gbGV2ZWwgcGVyIHBlcnNvbiBpbiB0aGF0IHJlZ2lvbiBhbmQgb2YgdGhhdCBnZW5kZXIgb2YgZmliZXIgaW4gZ3JhbXMgcGVyIGRheS4KClRoZSBzZWNvbmQgY3N2IGZpbGUgaGFzIHNpbWlsYXIgZGF0YSwgYnV0IGNvbnN1bXB0aW9uIGxldmVscyBmb3IgZGlmZmVyZW50IGFnZSBncm91cHMgYXJlIHNlcGFyYXRlZC4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNzAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJhZ2Vfc2VwMy5wbmciKSkKYGBgCgpUaGUgYXV0aG9ycyBvZiB0aGlzIGFydGljbGUgb2J0YWluZWQgdGhlIGRhdGEgZnJvbSBhIHZhcmlldHkgb2Ygc291cmNlcyBpbmNsdWRpbmcgaG91c2Vob2xkIGJ1ZGpldCBzdXJ2ZXlzIGFuZCBudXRyaXRpb25hbCBzdXJ2ZXlzIHJlZ2FyZGluZyAyNCBob3VyIHJlY2FsbCBvZiBmb29kIGNvbnN1bXB0aW9uIGFuZCAyNCBob3VyIHVucmluYXJ5IHNvZGl1bSBhbmFseXNpcy4gVGhlIGF0YSB3YXMgZGVyaXZlZCBmcm9tIHNhbGVzIGRhdGEgZnJvbSBFdXJvbW9uaXRvciwgZGF0YSBmcm9tIHRoZSBVbml0ZWQgTmF0aW9ucyBGb29kIGFuZCBBZ3JpY3VsdHVyZSBPcmdhbml6YXRpb24gKEZBTyksIGVzdGltYXRlcyBhYm91dCBuYXRpb25hbCBhdmFpbGFiaWxpdHkgb2Ygc3BlY2lmaWMgbnV0cmllbnRzLCBmcm9tIHRoZSBTdXBwbHkgVXRpbGF6YXRpb24gQWNjb3VudHMoU1VBKSwgYW5kIHRoZSBVbml0ZWQgU3RhdGVzIERlcGFydG1lbnQgb2YgQWdyaWN1bHR1cmUncyBOYXRpb25hbCBOdXRyaXRpb24gRGF0YWJhc2UuCgoKPHU+Tm90ZTo8L3U+IFdoaWxlIFtnZW5kZXJdKGh0dHBzOi8vd3d3LmdlbmRlcnNwZWN0cnVtLm9yZy9xdWljay1saW5rcy91bmRlcnN0YW5kaW5nLWdlbmRlci8pe3RhcmdldD0iX2JsYW5rIn0gYW5kIFtzZXhdKGh0dHBzOi8vd3d3Lndoby5pbnQvZ2Vub21pY3MvZ2VuZGVyL2VuL2luZGV4MS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGFyZSBub3QgYWN0dWFsbHkgYmluYXJ5LCB0aGUgZGF0YSBwcmVzZW50ZWQgdGhhdCBpcyB1c2VkIGluIHRoaXMgYW5hbHlzaXMgb25seSBjb250YWlucyBkYXRhIGZvciBncm91cHMgb2YgaW5kaXZpZHVhbHMgZGVzY3JpYmVkIGFzIG1lbiBvciB3b21lbi4gCgojIyBEYXRhIEltcG9ydAoKTGV0J3MgaW1wb3J0IG91ciBkYXRhIGludG8gUiBub3cgc28gdGhhdCB3ZSBjYW4gZXhwbG9yZSB0aGUgZGF0YSBmdXJ0aGVyLgoKYGBge3J9CmRpZXRfZGF0YSA8LXJlYWRyOjpyZWFkX2NzdihoZXJlKCJkb2NzIiwgImRpZXRhcnlfcmlza19leHBvc3VyZV9hbGxfYWdlc18yMDE3LmNzdiIpKQpzZXBfYWdlX2RpZXRfZGF0YSA8LXJlYWRfY3N2KGhlcmUoImRvY3MiLCAiZGlldGFyeV9yaXNrX2V4cG9zdXJlX3NlcF9hZ2VzXzIwMTcuY3N2IikpCmBgYAoKCkZpcnN0IGxldCdzIGp1c3QgZ2V0IGEgZ2VuZXJhbCBzZW5zZSBvZiBvdXIgZGF0YS4gV2UgY2FuIGRvIHRoYXQgdXNpbmcgdGhlIGBnbGltcHNlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgKGl0IGlzIGFsc28gaW4gdGhlIGB0aWJibGVgIHBhY2thZ2UpLgoKYGBge3J9CmRwbHlyOjpnbGltcHNlKGRpZXRfZGF0YSkKYGBgCgpgYGB7cn0KZ2xpbXBzZShzZXBfYWdlX2RpZXRfZGF0YSkKYGBgCkhlcmUgd2UgY2FuIHRlbGwgdGhhdCB0aGUgYHNlcF9hZ2VfZGlldF9kYXRhYCBpcyBtdWNoIGxhcmdlciB0aGFuIHRoZSBgZGlldF9kYXRhYC4gVGhlcmUgYXJlIDg4LDIwMCByb3dzISBUaGUgZGlldF9kYXRhIGhhcyBvbmx5IDUsODgwIHJvd3MuCkhvd2V2ZXIsIGJvdGggZmlsZXMgYXBwZWFyIHRvIGhhdmUgdGhlIHNhbWUgY29sdW1uIHN0cnVjdHVyZSB3aXRoIDExIHZhcmlhYmxlcyBlYWNoLgoKCgpUaGUgYHNraW0oKWAgZnVuY3Rpb24gb2YgdGhlIGBza2ltcmAgcGFja2FnZSBpcyBhbHNvIHJlYWxseSBoZWxwZnVsIGZvciBnZXR0aW5nIGEgZ2VuZXJhbCBzZW5zZSBvZiB5b3VyIGRhdGEuCgpgYGB7Un0Kc2tpbShkaWV0X2RhdGEpCmBgYAoKTm90aWNlIGhvdyB0aGVyZSBpcyBhIGNvbHVtbiBhYm91dCB0aGUgdmFsdWVzIHRoYXQgYXJlIG1pc3NpbmcuIEl0IGxvb2tzIGxpa2Ugb3VyIGRhdGEgaXMgdmVyeSBjb21wbGV0ZSBhbmQgd2UgZG8gbm90IGhhdmUgYW55IG1pc3NpbmcgZGF0YS4KV2UgYWxzbyBnZXQgYSBzZW5zZSBhYm91dCB0aGUgc2l6ZSBvZiBvdXIgZGF0YS4KClRoZSBgbl91bnFpdWVgIGNvbHVtbiBzaG93cyB1cyB0aGUgbnVtYmVyIG9mIHVucWl1ZSB2YWx1ZXMgZm9yIGVhY2ggb2Ygb3VyIGNvbHVtbnMuCgpMZXQncyB0YWtlIGEgbG9vayBhdCBgc2VwX2FnZV9kaWV0X2RhdGFgLgoKYGBge1J9CnNraW0oc2VwX2FnZV9kaWV0X2RhdGEpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSBtYW55IG1vcmUgcm93cyBpbiB0aGlzIGRhdGFzZXQuCgoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGRpZmZlcmVudCBkaWV0YXJ5IHJpc2sgZmFjdG9ycyBjb25zaWRlcmVkLgpUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgZGlzdGluY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4KClRoaXMgZnVuY3Rpb24gZ3JhYnMgb25seSB0aGUgZGlzdGluY3Qgb3IgdW5pcXVlIHJvd3MgZnJvbSBhIGdpdmVuIHZhcmlhYmxlIChyZWlfbmFtZSwgaW4gb3VyIGNhc2UpIG9mIGEgZ2l2ZW4gZGF0YSBmcmFtZSAoZGlldF9kYXRhLCBpbiBvdXIgY2FzZSkuCgpgYGB7cn0KI2Rpc3RpbmN0KHRpYmJsZV9uYW1lLCBjb2x1bW5fbmFtZSkKICBkcGx5cjo6ZGlzdGluY3QoZGlldF9kYXRhLCByZWlfbmFtZSkKYGBgCgpXZSB3aWxsIGJlIHVzaW5nIHRoZSBgJT4lYCBwaXBlIGZvciBzZXF1ZW50aWFsIHN0ZXBzIGluIG91ciBjb2RlIGxhdGVyIG9uLgpUaGlzIHdpbGwgbWFrZSBtb3JlIHNlbnNlIHdoZW4gd2UgaGF2ZSBtdWx0aXBsZSBzZXF1ZW50aWFsIHN0ZXBzIHVzaW5nIHRoZSBzYW1lIGRhdGEgb2JqZWN0LgoKCldlIGNvdWxkIGRvIHRoZSBzYW1lIGNvZGUgYXMgYWJvdmUgdXNpbmcgdGhpcyBub3RhdGlvbi4gRm9yIGV4YW1wbGUgd2UgZmlyc3QgZ3JhYiB0aGUgZGlldF9kYXRhLCB0aGVuIHdlIHNlbGVjdCB0aGUgZGlzdGluY3QgdmFsdWVzIG9mIHRoZSByZWlfbmFtZSB2YXJpYWJsZS4KCmBgYHtyfQpkaWV0X2RhdGEgJT4lCiAgZGlzdGluY3QocmVpX25hbWUpCmBgYAoKT2ssIHNvIHRoYXQgZ2l2ZXMgdXMgYW4gaWRlYSBvZiB3aGF0IGRpZXRhcnkgZmFjdG9ycyB3ZSBjYW4gZXhwbG9yZS4gCgpMZXQncyBzZWUgaWYgdGhlIGxvY2F0aW9uX25hbWUgdmFsdWVzIGFyZSB0aGUgc2FtZSBiZXR3ZWVuIGJvdGggY3N2IGZpbGVzLiBUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgc2V0ZXF1YWwoKWAgZnVuY3Rpb24gb2YgYGRwbHlyYC4KYGBge3J9CmRwbHlyOjpzZXRlcXVhbCgKICBkaXN0aW5jdChkaWV0X2RhdGEsbG9jYXRpb25fbmFtZSksIAogIGRpc3RpbmN0KHNlcF9hZ2VfZGlldF9kYXRhLCBsb2NhdGlvbl9uYW1lKSkgCmBgYAoKT2ssIHdlIGdvdCB0aGUgdmFsdWUgb2YgVFJVRSwgc28gaXQgbG9va3MgbGlrZSB0aGUgc2FtZSBsb2NhdGlvbnMgYXJlIGluIGJvdGggZmlsZXMuCgpOb3RlOiBJbiB0aGlzIGNhc2Ugd2VyZSBjb21wYXJpbmcgdHdvIGRpZmZlcmVudCBvYmplY3RzIHNvIHVzaW5nIHRoZSBwaXBlIGlzIG5vdCBhcyB1c2VmdWwuCgpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgbG9jYXRpb25zIGluY2x1ZGVkIGluIHRoZSBkYXRhLgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KI3Njcm9sbCB0aHJvdWdoIHRoZSBvdXRwdXQhCnNlcF9hZ2VfZGlldF9kYXRhICU+JQogZGlzdGluY3QobG9jYXRpb25fbmFtZSklPiUKICBwdWxsKCkKYGBgCiMjIyMKCgpPSywgc28gdGhlcmUgYXJlIGdsb2JhbCB2YWx1ZXMsIGFzIHdlbGwgYXMgdmFsdWVzIGZvciAxODUgY291bnRyaWVzLgoKCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBkYXRhIHdoZW4gd2Ugb3JkZXIgaXQgYnkgdGhlIG1lYW4gY29uc3VtcHRpb24gcmF0ZSBjb2x1bW46CgpgYGB7cn0KZGlldF9kYXRhICU+JQogIGFycmFuZ2UobWVhbikgJT4lCiAgZ2xpbXBzZSgpCgpgYGAKT2ssIHNvIGl0IGxvb2tzIGxpa2UgcGVvcGxlIGluIExlYmFub24gZG9udCBlYXQgdmVyeSBtYW55IHRyYW5zIGZhdHR5IGFjaWRzLgoKCkxldCdzIGFsc28gZmlndXJlIG91dCBob3cgbWFueSB2YWx1ZXMgdGhlcmUgYXJlIGluIGVhY2ggYWdlIGdyb3VwIG9mIHRoZSBkYXRhIHRoYXQgaXMgc2VwYXJhdGVkIGJ5IGFnZS4KYGBge3J9CnNlcF9hZ2VfZGlldF9kYXRhICU+JQpkcGx5cjo6Y291bnQoYWdlX2dyb3VwX25hbWUpCmBgYApUaGF0J3MgYSBsb3Qgb2YgdmFsdWVzIQoKTGV0J3MgbG9vayBhIGJpdCBkZWVwZXIgdG8gdHJ5IHRvIHVuZGVyc3RhbmQgd2h5LgpXZSBjYW4gdXNlIHRoZSBjb3VudCBmdW5jdGlvbiBhZ2FpbiBidXQgZ2V0IHRoZSBudW1iZXIgb2YgdmFsdWVzIGZvciBlYWNoIGNhdGVnb3J5IHdpdGhpbiBzZXgsIGFnZV9ncm91cF9uYW1lIGFuZCBsb2NhdGlvbl9uYW1lIG9mIHRoZSBkYXRhLgpgYGB7cn0Kc2VwX2FnZV9kaWV0X2RhdGElPiUKICBjb3VudChzZXgsYWdlX2dyb3VwX25hbWUsIGxvY2F0aW9uX25hbWUpCmBgYAoKT2ssIHNvIGl0IGxvb2tzIGxpa2UgdGhlcmUgYXJlIHByb2JhYmx5IHRoZSBjb25zdW1wdGlvbiB2YWx1ZXMgZm9yIGVhY2ggb2YgdGhlIGRpZmZlcmVudCBkaWV0YXJ5IGZhY3RvcnMod2hpY2ggdGhlcmUgd2VyZSAxNSBkaWZmZXJlbnQgZmFjdG9ycykgZm9yIGVhY2ggYWdlIGdyb3VwLCBmb3IgZWFjaCBnZW5kZXIsIGFuZCBmb3IgZWFjaCBjb3VudHJ5LgoKV2UgY2FuIGNvbmZpcm0gdGhpcyBieSBmaWx0ZXJpbmcgdGhlIGRhdGEgdG8gb25lIG9mIHRoZSBhZ2UgZ3JvdXBzLCBmb3IgYSBzaW5nbGUgZ2VuZGVyLCBhbmQgZm9yIGEgc2luZ2xlIGxvY2F0aW9uLgoKYGBge3J9CnNlcF9hZ2VfZGlldF9kYXRhICU+JQpmaWx0ZXIoIHNleCA9PSAiRmVtYWxlIiwKICAgICAgICBhZ2VfZ3JvdXBfbmFtZSA9PSAiMjUgdG8gMjkiLAogICAgICAgIGxvY2F0aW9uX25hbWUgPT0gIkFmZ2hhbmlzdGFuIikKYGBgCgoKTGV0J3MgYWxzbyBnZXQgdGhlIGRhdGEgZnJvbSB0aGUgUERGIG9mIHRoZSBwYXBlciBzbyB0aGF0IHdlIGNhbiBjYWxjdWxhdGUgY29uc3VtcHRpb24gb2YgdGhlc2UgZGlldGFyeSBmYWN0b3JzIGFzIHBlcmNlbnRhZ2Ugb2YgZGFpbHkgcmVxdWlyZW1lbnQsIHdoaWNoIHdvdWxkIGJlIG1vcmUgaW50ZXJwcmV0YWJsZS4KCldlIGFyZSBpbnRlcmVzdGVkIGluIHRoaXMgdGFibGUgb24gcGFnZSAzOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjcwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIlRhYmxlLnBuZyIpKQpgYGAKCgpGaXJzdCBsZXQncyBpbXBvcnQgdGhlIFBERiB1c2luZyB0aGUgYHBkZnRvb2xzYCBwYWNrYWdlLgpgYGB7cn0KcGFwZXI8LXBkZnRvb2xzOjpwZGZfdGV4dChoZXJlKCJkb2NzIiwgIkFmc2hpbiBldCBhbC4gMjAxOSAtIEhlYWx0aCBlZmZlY3RzIG9mIGRpZXRhcnkgcmlza3MgaW4gMTk1IGNvdW50cmllcywgIC4uLiAxNyAtIGEgc3lzdGVtYXRpYyBhbmFseXNpcyBmb3IgdGhlIEdsb2JhbCBCdXJkZW4gb2YgRGlzZWFzZSBTdHVkeSAyMDE3LnBkZiIpKQpgYGAKCldlIGNhbiB1c2UgdGhlIGBiYXNlYCBgc3VtbWFyeSgpYCBmdW5jdGlvbiB0byBnZXQgYSBzZW5zZSBvZiB3aGF0IHRoZSBkYXRhIGxvb2tzIGxpa2UuIEJ5IGBiYXNlYCB3ZSBtZWFuIHRoYXQgdGhlc2UgZnVuY3Rpb25zIGFyZSBwYXJ0IG9mIHRoZSBgYmFzZWAgcGFja2FnZSBhbmQgYXJlIGxvYWRlZCBhdXRvbWF0aWNhbGx5LlRodXMgYGxpYnJhcnkoYmFzZSlgIGlzIG5vdCByZXF1aXJlZC4KYGBge3J9CnN1bW1hcnkocGFwZXIpCiNUaGlzIGlzIGVxdWl2YWxlbnQgdG8gdGhlIGZvbGxvd2luZywgYnV0IHRoaXMgaXMgdW5lY2Vzc2FyeToKI2Jhc2U6OnN1bW1hcnkocGFwZXIpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHdlIGhhdmUgMTUgZGlmZmVyZW50IGNoYXJhY3RlciBzdHJpbmdzLiBFYWNoIG9uZSBjb250YWlucyB0aGUgdGV4dCBvbiBlYWNoIG9mIHRoZSAxNSBkaWZmZXJlbnQgcGFnZXMgb2YgdGhlIFBERi4KCgojIyBEYXRhIFdyYW5nbGluZwoKQWdhaW4sIHRoZSB0YWJsZSB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBpcyBvbiB0aGUgdGhpcmQgcGFnZSwgc28gbGV0J3MgZ3JhYiBqdXN0IHRoYXQgcG9ydGlvbiBvZiB0aGUgUERGLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjcwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInBhZ2UzLnBuZyIpKQpgYGAKCmBgYHtyfQojSGVyZSB3ZSB3aWxsIHNlbGVjdCB0aGUgM3JkIHZhbHVlIGluIHRoZSBwYXBlciBvYmplY3QKdGFibGUgPC0gcGFwZXJbM10KCnN1bW1hcnkodGFibGUpCgoKZ2xpbXBzZSh0YWJsZSwgbmNoYXIubWF4ID0gODAwKQoKCmBgYAoKSGVyZSB3ZSBjYW4gc2VlIHRoYXQgdGhlIGB0YWJsZWAgb2JqZWN0IG5vdyBjb250YWlucyB0aGUgdGV4dCBmcm9tIHRoZSAzcmQgcGFnZSBhcyBhICpzaW5nbGUgbGFyZ2UgY2hhcmFjdGVyIHN0cmluZyouIEhvd2V2ZXIgdGhlIHRleHQgaXMgZGlmZmljdWx0IHRvIHJlYWQgYmVhY3VzZSBvZiB0aGUgY29sdW1uIHN0cnVjdHVyZSBpbiB0aGUgcGRmLiBOb3cgbGV0J3MgdHJ5IHRvIGdyYWIganVzdCB0aGUgdGV4dCBpbiB0aGUgdGFibGUuCgpPbmUgd2F5IHRvIGFwcHJvYWNoIHRoaXMgaXMgdG8gc3BsaXQgdGhlIHN0cmluZyBieSBzb21lIHBhdHRlcm4gdGhhdCB3ZSBub3RpY2UgaW4gdGhlIHRhYmxlLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjcwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIlRhYmxlLnBuZyIpKQpgYGAKCk9ubHkgdGhlIGNhcGl0YWxpemVkIGZvcm0gb2YgdGhlIHdvcmQgIkRpZXQiIGFwZWFycyB0byBiZSB3aXRoaW4gdGhlIHRhYmxlLCBhbmQgaXMgbm90IHByZXNlbnQgaW4gdGhlIHByZWNlZGluZyB0ZXh0IChhbHRvdWdoICJkaWV0IiBpcykuIEFsbCB0aGUgcm93cyBvZiBpbnRlcmVzdCBvZiB0aGUgdGFibGUgYXBwZWFyIHRvIHN0YXJ0IHdpdGggdGhlIHdvcmQgIkRpZXQiLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjcwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIkRpZXRfb25fcGFnZTMucG5nIikpCmBgYAoKCkxldCdzIHVzZSB0aGUgYHN0cl9zcGxpdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UgdG8gc3BsaXQgdGhlIGRhdGEgd2l0aGluIHRoZSBvYmplY3QgY2FsbGVkIGB0YWJsZWBieSB0aGUgd29yZCAiRGlldCIuICBPbmx5IGxpbmVzIGZyb20gcGFnZSAzIHRoYXQgY29udGFpbiB0aGUgd29yZCBgRGlldGAgd2lsbCBiZSBzZWxlY3RlZCAoYW5kIG5vdCAiZGlldCIgYXMgdGhpcyBmdW5jdGlvbiBpcyBjYXNlLXNlbnNpdGl2ZSkuIEVhY2ggc2VjdGlvbiBvZiB0aGUgdGV4dCB0aGF0IGNvbnRpYW5zICJEaWV0IiB3aWxsIGJlIHNwbGl0IGludG8gaW5kaXZpZHVhbCBwaWVjZXMgZXZlcnl0aW1lIHRoZSB3b3JsZCAiRGlldCIgb2NjdXJzIGFuZCB0aGUgd29yZCBpdHNlbGYgd2lsbCBiZSByZW1vdmVkLgoKSW4gdGhpcyBjYXNlIHdlIGFyZSBhbHNvIHVzaW5nIHRoZSBtYWdyaXR0ciBhc3NpZ25tZW50IHBpcGUgb3IgZG91YmxlIHBpcGUgdGhhdCBsb29rcyBsaWtlIHRoaXMgYCU8PiVgLiBUaGlzIGFsbG93cyB1cyB1c2UgdGhlIHRhYmxlIGRhdGEgYXMgaW5wdXQgdG8gdGhlIGxhdGVyIHN0ZXBzIGJ1dCBhbHNvIHJlYXNzaWduIHRoZSBvdXRwdXQgdG8gdGhlIHNhbWUgZGF0YSBvYmplY3QgbmFtZS4KCmBgYHtyfQp0YWJsZSAlPD4lCiAgc3RyaW5ncjo6c3RyX3NwbGl0KHBhdHRlcm4gPSAnRGlldCcpCmBgYAoKVXNpbmcgIHRoZSBgYmFzZTo6c3VtbWFyeSgpYCBhbmQgYGRwbHlyOjpnbGltcHNlKClgIGZ1bmN0aW9uIHdlIGNhbiBzZWUgdGhhdCB3ZSBjcmVhdGVkIGEgbGlzdCBvZiB0aGUgcm93cyBpbiB0aGUgdGFibGUgdGhhdCBjb250YWluIHRoZSB3b3JkICJEaWV0Ii4gV2UgY2FuIHNlZSB0aGF0IHdlIHN0YXJ0IHdpdGggdGhlIHJvdyB0aGF0IGNvbnRhaW5zICJEaWV0IGxvdyBpbiBmcnVpdHMiLiAKCmBgYHtyfQp0YWJsZSAlPiUKIHN1bW1hcnkoKQpgYGAKCmBgYHtyfQp0YWJsZSAlPiUKICBnbGltcHNlKCkKYGBgClJTdHVkaW8gY3JlYXRlcyByZWFsbHkgY2hlYXRzaGVldHMgbGlrZSB0aGlzIG9uZSB3aGljaCBzaG93cyB5b3UgYWxsIHRoZSBtYWpvciBmdW5jdGlvbnMgaW4gYHN0cmluZ3JgLiBZb3UgY2FuIGRvd25sb2FkIG90aGVycyBbaGVyZV0oaHR0cHM6Ly9yc3R1ZGlvLmNvbS9yZXNvdXJjZXMvY2hlYXRzaGVldHMvKXt0YXJnZXQ9Il9ibGFuayJ9LgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjcwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInN0cmluZ3MtMV9zdHJfc3BsaXQucG5nIikpCmBgYAoKWW91IGNhbiBzZWUgdGhhdCB3ZSBjb3VsZCBoYXZlIGFsc28gdXNlZCB0aGUgYHN0cl9zcGxpdF9maXhlZCgpYCBmdW5jdGlvbiB3aGljaCB3b3VsZCBhbHNvIHNlcGFyYXRlIHRoZSBzdWJzdHJpbmdzIGludG8gZGlmZmVyZW50IGNvbHVtbnMgb2YgYSBtYXRyaXgsIGhvd2V2ZXIgd2Ugd291bGQgbmVlZCB0byBrbm93IHRoZSBudW1iZXIgb2Ygc3Vic3RyaW5ncyBvciBwaWVjZXMgdGhhdCB3ZSB3b3VsZCBsaWtlIHJldHVybmVkLgoKRm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgYHN0cl9zcGxpdCgpYCBzZWUgW2hlcmVdKGh0dHA6Ly9yZnVuY3Rpb24uY29tL2FyY2hpdmVzLzE0OTkpe3RhcmdldD0iX2JsYW5rIn0uCgoKTGV0J3Mgc2VwYXJ0ZSB0aGUgdmFsdWVzIHdpdGhpbiB0aGUgbGlzdCB1c2luZyB0aGUgYmFzZSBgdW5saXN0YCBmdW5jdGlvbiwgdGhpcyB3aWxsIGFsbG93IHVzIHRvIGVhc2lseSBzZWxlY3QgdGhlIGRpZmZlcmVudCBzdWJzdHJpbmdzIHdpdGhpbiB0aGUgb2JqZWN0IGNhbGxlZCBgdGFibGVgLgoKYGBge3J9CnRhYmxlICU8PiUKICB1bmxpc3QoKQpgYGAKCkl0J3MgaW1wb3J0YW50IHRvIHJlYWxpemUgdGhhdCB0aGUgZmlyc3Qgc3BsaXQgd2lsbCBzcGxpdCB0aGUgdGV4dCBiZWZvcmUgdGhlIGZpcnN0IG9jY3VyYW5jZSBvZiBgRGF0YWAgYXMgdGhlIGZpcnN0IHZhbHVlIGluIHRoZSBvdXRwdXQuIFdlIGNvdWxkIHVzZSB0aGUgYGZpcnN0KClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gbG9vayBhdCB0aGlzIHZhbHVlLiBIb3dldmVyLCB3ZSB3aWxsIHN1cHByZXNzIHRoZSBvdXRwdXQgYXMgdGhpcyBpcyBxdWl0ZSBsYXJnZS4KCmBgYHtyLCBldmFsID0gRkFMU0V9CmRwbHlyOjpmaXJzdCh0YWJsZSkKYGBgCgpJbnN0ZWFkIHdlIGNhbiB0YWtlIGEgbG9vayBhdCB0aGUgc2Vjb25kIGVsZW1lbnQgb2YgdGhlIGxpc3QuIHVzaW5nIHRoZSBgbnRoKClgIGZ1bmN0aW9uIG9mIGBkcGx5cmAuCgpgYGB7cn0KbnRoKHRhYmxlLCAyKQpgYGAKCkluZGVlZCB0aGlzIGxvb2tzIGxpa2UgdGhlIGZpcnN0IHJvdyBvZiBpbnRlcmVzdCBpbiBvdXIgdGFibGU6CgpgYGB7cixlY2hvID0gRkFMU0Usb3V0LndpZHRoPSAiNzAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiZmlyc3Ryb3cucG5nIikpCmBgYAoKClVzaW5nIHRoZSBgbGFzdCgpYCBhbmQgdGhlIGBudGgoKWAgZnVuY3Rpb25zIG9mIHRoZSBgZHBseXJgIHBhY2thZ2Ugd2UgY2FuIHRha2UgYSBsb29rIGF0IHRoZSBsYXN0IHZhbHVlcyBvZiB0aGUgbGlzdC4KYGBge3J9CiN0byBzZWUgdGhlIHNlY29uZCB0byBsYXN0IHZhbHVlIHdlIGNhbiB1c2UgbnRoKCkKI3RoZSAtMiBzcGVjaWZpZXMgdGhhdCB3ZSB3YW50IHRoZSBzZWNvbmQgdG8gbGFzdCB2YWx1ZQojLTMgd291bGQgYmUgdGhpcmQgdG8gbGFzdCBhbmQgLTEgd291bGQgYmUgdGhlIGxhc3QgdmFsdWUKZHBseXI6Om50aCh0YWJsZSwgLTIpCgojdG8gc2VlIHRoZSB2ZXJ5IGxhc3QgdmFsdWUgd2UgY2FuIHVzZSBsYXN0KCkKZHBseXI6Omxhc3QodGFibGUpCgpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI3MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJlbmRfb2ZfdGFibGUucG5nIikpCmBgYAoKClRoZXJlZm9yZSwgd2UgZG9udCBuZWVkIHRoaXMgcGFydCBvZiB0aGUgdGFibGUgb3IgdGhlIHRleHQgYmVmb3JlIHRoZSB0YWJsZSBpZiB3ZSBqdXN0IHdhbnQgdGhlIGNvbnN1bXB0aW9uIHJlY2NvbWVuZGF0aW9ucy4gCgpTbyB3ZSB3aWxsIHNlbGVjdCB0aGUgMm5kIHRocm91Z2ggdGhlIHNlY29uZCB0byBsYXN0IG9mIHRoZSBzdWJzdHJpbmdzLiBTaW5jZSB3ZSBoYXZlIDE3IHN1YnN0cmluZ3MsIHdlIHdpbGwgc2VsZWN0IHRoZSAybmQgdGhyb3VnaCB0aGUgMTZ0aC4gSG93ZXZlciBhIGJldHRlciB3YXkgdG8gZG8gdGhpcyByYXRoZXIgdGhhbiBzZWxlY3RpbmcgYnkgaW5kZXgsIHdvdWxkIGJlIHRvIHNlbGVjdCBwaHJhc2VzIHRoYXQgYXJlIHVuaXF1ZSB0byB0aGUgdGV4dCB3aXRoaW4gdGhlIHRhYmxlIHRoYXQgd2Ugd2FudC4gV2Ugd2lsbCB1c2UgdGhlIGBzdHJfc3Vic2V0KClgIGZ1bmN0aW9uIG9mIGBzdHJpbmdyYCBwYWNrYWdlIHRvIHNlbGVjdCB0aGUgdGFibGUgcm93cyB3aXRoIGNvbnN1bXB0aW9uIGd1aWRsaW5lcy4gIE1vc3Qgb2YgdGhlIHJvd3MgaGF2ZSB0aGUgcGhyYXNlIiBNZWFuIGRhaWx5IGNvbnN1bXB0aW9uIiwgaG93ZXZlciwgdGhlcmUgYXJlIG90aGVyIHBocmFzZXMgZm9yIHNvbWUgb2YgdGhlIHJvd3MsIGluY2x1ZGluZyAiTWVhbiBkYWlseSBpbnRha2UiIGFuZCAiMjQgaCBzb2RpdW0iCgpgYGB7cn0KIyBvbmUgY291bGQgc3Vic2V0IHRoZSB0YWJsZSBsaWtlIHRoaXM6CiN0YWJsZSA8LSB0YWJsZVsyOjE2XQoKdGFibGUgJTw+JQpzdHJfc3Vic2V0KHBhdHRlcm4gPSAiTWVhbiBkYWlseSBjb25zdW1wdGlvbnxNZWFuIGRhaWx5IGludGFrZXwyNCBoIikKYGBgCgpOb3RpY2UgdGhhdCB3ZSBzcGVwYXJhdGUgdGhlIGRpZmZlcmVudCBwYXR0ZXJucyB0byBsb29rIGZvciB1c2luZyB2ZXJ0aWNhbCBiYXIgY2hhcmFjdGVyICJ8IiBhbmQgdGhhdCBhbGwgb2YgdGhlIHBhdHRlcm5zIGFyZSB3aXRoaW4gcXVvdGF0aW9uIG1hcmtzIHRvZ2V0aGVyLgoKIyMjIyB7LnF1ZXN0aW9uX2Jsb2NrfQo8dT5RdWVzdGlvbiBvcHBvcnR1bml0eTo8L3U+IAoKMSkgV2hhdCBvdGhlciBzdHJpbmcgcGF0dGVybnMgY291bGQgeW91IHVzZSB0byBzdWJzZXQgdGhlIHJvd3Mgb2YgdGhlIHRhYmxlIHRoYXQgd2Ugd2FudD8KCjIpIFdoeSBtaWdodCBpdCBiZSBiZXR0ZXIgdG8gc3Vic2V0IGJhc2VkIG9uIHRoZSB0ZXh0IHJhdGhlciB0aGFuIHRoZSBpbmRleD8KCiMjIyMKCgpOb3cgdGhlIGZpcnN0IHJvdyBpcyB3aGF0IHdlIHdhbnQ6CmBgYHtyfQpmaXJzdCh0YWJsZSkKYGBgCgpBbmQgdGhlIGxhc3Qgcm93IGlzIHdoYXQgd2Ugd2FudDoKYGBge3J9Cmxhc3QodGFibGUpCmBgYAoKTm90aWNlIHRoYXQgdGhlcmUgdGhlIGRlY2ltYWwgcG9pbnRzIGZyb20gdGhlIHBkZiBhcmUgYmVpbmcgcmVjb2duaXplZCBhcyBhbiBpbnRlcnB1bmN0IGluc3RlYWQgb2YgYSBwZXJpb2Qgb3IgZGVjaW1hbC4gQW4gaW50ZXJwdW5jdCBpcyBhIGNlbnRlcmVkIGRvdCwgYXMgb3Bwb3NlZCB0byBhIHBlcmlvZCBvciBkZWNpbWFsIHRoYXQgaXMgYWxpZ25lZCB0byB0aGUgYm90dG9tIG9mIHRoZSBsaW5lLgoKVGhlIGludGVycHVuY3Qgd2FzIHByZXZpb3VzbHkgdXNlZCB0byBzZXBhcmF0ZSB3b3JkcyBpbiBjZXJ0YWluIGxhbmd1YWdlcywgbGlrZSBhbmNpZW50IExhdGluLgoKCgo8cCBhbGlnbj0iY2VudGVyIj4KICA8aW1nIHdpZHRoPSI0MDAiIHNyYz0iaHR0cHM6Ly93d3cueW91cmRpY3Rpb25hcnkuY29tL2ltYWdlL2FydGljbGVzLzM0MTcuTGF0aW4uanBnIj4KPC9wPgoKIyMjIyMjIFtbc291cmNlXShodHRwczovL3d3dy55b3VyZGljdGlvbmFyeS5jb20vaW1hZ2UvYXJ0aWNsZXMvMzQxNy5MYXRpbi5qcGcpXQoKWW91IGNhbiBwcm9kdWNlIGFuIGludGVycHVuY3Qgb24gYSBtYWMgbGlrZSB0aGlzOgoKCjxwIGFsaWduPSJjZW50ZXIiPgogIDxpbWcgd2lkdGg9IjQwMCIgc3JjPSJodHRwczovL3d3dy5zaG9ydHR1dG9yaWFscy5jb20vbWFjLW9zLXNwZWNpYWwtY2hhcmFjdGVycy1zaG9ydGN1dHMvaW1hZ2VzL21pZGRsZS1kb3QucG5nIj4KPC9wPgoKIyMjIyMjIFtbc291cmNlXShodHRwczovL3d3dy5zaG9ydHR1dG9yaWFscy5jb20vbWFjLW9zLXNwZWNpYWwtY2hhcmFjdGVycy1zaG9ydGN1dHMvbWlkZGxlLWRvdC5odG1sKV0KCgpJdCBpcyBpbXBvcnRhbnQgdG8gcmVwbGFjZSB0aGVzZSBmb3IgbGF0ZXIgd2hlbiB3ZSB3YW50IHRoZXNlIHZhbHVlcyB0byBiZSBjb252ZXJ0ZWQgZnJvbSBjaGFyYWN0ZXIgc3RyaW5ncyB0byBudW1lcmljLiBXZSB3aWxsIGFnYWluIHVzZSB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuIFRoaXMgdGltZSB3ZSB3aWxsIHVzZSB0aGUgYHN0cl9yZXBsYWNlX2FsbCgpYCBmdW5jdGlvbiB3aGljaCByZXBsYWNlcyBhbGwgaW5zdGFuY2VzIG9mIGEgcGF0dGVybiBpbiBhbiBpbmRpdmlkdWFsIHN0cmluZy4gSW4gdGhpcyBjYXNlIHdlIHdhbnQgdG8gcmVwbGFjZSBhbGwgaW5zdGFuY2VzIG9mIHRoZSBpbnRlcnB1bmN0IHdpdGggYSBkZWNpbWFsIHBvaW50LgoKCmBgYHtyLH0KdGFibGUgJTw+JQogIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCggcGF0dGVybiA9ICLCtyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiLiIpCmBgYAoKCk5vdyB3ZSB3aWxsIHRyeSB0byBzcGxpdCB0aGUgc3RyaW5ncyBmb3IgZWFjaCByb3cgYmFzZWQgb24gdGhlIHByZXNlbmNlIG9mICAyIHNwYWNlcyB0byBjcmVhdGUgdGhlIGNvbHVtbnMgb2YgdGhlIHRhYmxlLCBhcyB0aGVyZSBhcHBlYXJzIHRvIGJlIGxhcmdlciB0aGFuIGEgc3BhY2UgYmV0d2VlbiB0aGUgY29sdW1ucyB0byBjcmVhdGUgc3Vic3RyaW5ncy4gVGhlIHN1YnN0cmluZ3Mgd2lsbCBiZSBzZXBhcmF0ZWQgYnkgcXVvdGVzLgoKYGBge3IsIGVjaG8gPSBGQUxTRSxvdXQud2lkdGggPSAiNzAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAic3RyaW5ncy0yX2hpZ2hsaWdodC5wbmciKSkKYGBgCgoKVGhlIHNlY29uZCBwYWdlIG9mIHRoZSBgc3RyaW5ncmAgY2hlZXRzaGVldCBoYXMgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB1c2luZyAiU3BlY2lhbCBDaGFyYWN0ZXJzIiBpbiBgc3RyaW5ncmAuIEZvciBleGFtcGxlIGBcXHNgIGlzIGludGVycHJldGVkIGFzIGEgc3BhY2UgYXMgdGhlIGBcXGAgaW5kaWNhdGVzIHRoYXQgdGhlIGBzYCBzaG91bGQgYmUgaW50ZXJwcmV0ZWQgYXMgYSBzcGVjaWFsIGNoYXJhY3RlciBhbmQgbm90IHNpbXBseSB0aGUgbGV0dGVyIHMuICBUaGUgezIsfSBpbmRpY2F0ZXMgMiBvciBtb3JlIHNwYWNlcywgd2hpbGUgezJ9IHdvdWxkIGluZGljYXRlIGV4YWN0bHkgMiBzcGFjZXMuCgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KdGFibGVfc3BsaXQgPC0gc3RyX3NwbGl0KHN0cmluZz10YWJsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuPSAiXFxzezIsfSIpCmdsaW1wc2UodGFibGVfc3BsaXQpICNzY3JvbGwgdGhlIG91dHB1dCEKYGBgCiMjIyMKCklmIHdlIGxvb2sgY2xvc2VseSwgd2UgY2FuIHNlZSB0aGF0IHRoZSBzdWdhci1zd2VldGVuZWQgYmV2ZXJhZ2UgYW5kIHRoZSBzZWFmb29kIGNhdGVnb3J5IGhhZCBvbmx5IG9uZSBzcGFjZSBiZXR3ZWVuIHRoZSBmaXJzdCBhbmQgc2Vjb25kIGNvbHVtbnMgLSB0aGUgY29sdW1ucyBhYm91dCB0aGUgZGlldGFyeSBjYXRlZ29yeSBhbmQgdGhlIG9uZSB0aGF0IGRlc2NyaWJlcyBpbiBtb3JlIGRldGFpbCB3aGF0IHRoZSBjb25zdW1wdGlvbiBzdWdnZXN0aW9uIGlzIGFib3V0LgoKVGhlIHZhbHVlcyBmb3IgdGhlc2UgdHdvIGNvbHVtbnMgYXBwZWFyIHRvIGJlIHRvZ2V0aGVyIHN0aWxsIGluIHRoZSBzYW1lIHN1YnN0cmluZyBmb3IgdGhlc2UgdHdvIGNhdGVnb3JpZXMuIFRoZXJlIGFyZSBubyBxdW90YXRpb24gbWFya3MgYWRqYWNlbnQgdG8gdGhlIHdvcmQgYCJNZWFuImAuCgpIZXJlIHlvdSBjYW4gc2VlIGhvdyB0aGUgbmV4dCBzdWJzdHJpbmcgc2hvdWxkIGhhdmUgc3RhcnRlZCB3aXRoIHRoZSB3b3JkIGAiTWVhbiJgIGJ5IHRoZSBuZXcgaW5jbHVzaW9uIG9mIGEgcXVvdGF0aW9uIG1hcmsgYCJgLiAKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI3MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJzdWJzdHJpbmdfc2VwLnBuZyIpKQpgYGAKCgpXZSBjYW4gYWRkIGFuIGV4dHJhIHNwYWNlIGluIGZyb250IG9mIHRoZSB3b3JkIGAiTWVhbiJgIGZvciB0aGVzZSBwYXJ0aWN1bGFyIGNhdGVnb3JpZXMgYW5kIHRoZW4gdHJ5IHNwbGl0dGluZyBhZ2Fpbi4KClNpbmNlIHdlIG9yZ2luYWxseSBzcGxpdCBiYXNlZCBvbiAyIG9yIG1vcmUgc3BhY2VzLCB3ZSBjYW4ganVzdCBhZGQgYSBzcGFjZSBpbiBmcm9udCBvZiB0aGUgd29yZCAiTWVhbiIgZm9yIGFsbCB0aGUgdGFibGUgc3RyaW5ncyBhbmQgdGhlbiB0cnkgc3Vic2V0dGluZyBhZ2Fpbi4KYGBge3J9CnRhYmxlJT4lCnN0cl93aGljaChwYXR0ZXJuID0gInNlYWZvb2R8c3VnYXIiKQpgYGAKCmBgYHtyfQp0YWJsZVs5XSA8LXN0cmluZ3I6OnN0cl9yZXBsYWNlKHBhdHRlcm4gPSAiTWVhbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIiBNZWFuIiwgdGFibGVbOV0pCnRhYmxlWzEyXSA8LXN0cmluZ3I6OnN0cl9yZXBsYWNlKHBhdHRlcm4gPSJNZWFuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0iIE1lYW4iLCB0YWJsZVsxMl0pCnRhYmxlX3NwbGl0IDwtIHN0cl9zcGxpdCh0YWJsZSxwYXR0ZXJuPSAiXFxzezIsfSIpCmBgYAoKV2UgY291bGQgYWxzbyBodXN0IGFkZCBhIHNwYWNlIGluIGZyb250IG9mIGFsbCB0aGUgdmFsdWVzIG9mIE1lYW4gaW4gdGhlIHRhYmxlIHNpbmNlIHRoZSBzcGxpdCB3YXMgcGVmb3JtZWQgYmFzZWQgb24gMiBvciBtb3JlIHNwYWNlcy4gVGh1cyB0aGUgb3RoZXIgZWxlbWVudHMgaW4gYHRhYmxlYCB3b3VsZCBhbHNvIGJlIHNwbGl0IGp1c3QgYXMgYmVmb3JlIGRlc3BpdGUgdGhlIGFkZGl0aW9uYWwgc3BhY2UuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQp0YWJsZTwtdGFibGUgJT4lCiAgc3RyaW5ncjo6c3RyX3JlcGxhY2UocGF0dGVybiA9Ik1lYW4iLCAKICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIgTWVhbiIpCnRhYmxlX3NwbGl0IDwtIHN0cl9zcGxpdCh0YWJsZSxwYXR0ZXJuPSAiXFxzezIsfSIpCmBgYAoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KI3Njcm9sbCB0aGUgb3V0cHV0IQpnbGltcHNlKHRhYmxlX3NwbGl0KSAKYGBgCiMjIyMKCkxvb2tzIGJldHRlciEKCldlIHdhbnQganVzdCB0aGUgZmlyc3QgKHRoZSBmb29kICoqY2F0ZWdvcnkqKikgYW5kIHRoaXJkIGNvbHVtbiAodGhlIG9wdGltYWwgY29uc3VtcHRpb24gKiphbW91bnQqKiBzdWdnZXN0ZWQpIGZvciBlYWNoIHJvdyBpbiB0aGUgdGFibGUuCgpXZSBjYW4gdXNlIHRoZSBgbWFwYCBmdW5jdGlvbiBvZiB0aGUgYHB1cnJyYCBwYWNrYWdlIHRvIGFjY29tcGxpc2ggdGhpcy4KClRoZSBgbWFwYCBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gcGVyZm9ybSB0aGUgc2FtZSBhY3Rpb24gbXVsdGlwbGUgdGltZXMgYWNyb3NzIGVhY2ggZWxlbWVudCB3aXRoaW4gYW4gb2JqZWN0LgoKVGhpcyBmb2xsb3dpbmcgd2lsbCBhbGxvdyB1cyB0byBzZWxlY3QgdGhlIDFzdCBvciAzcmQgc3Vic3RyaW5nIGZyb20gZWFjaCBlbGVtZW50IG9mIHRoZSBgdGFibGVgIG9iamVjdC4KCmBgYHtyfQpjYXRlZ29yeSA8LW1hcCh0YWJsZV9zcGxpdCwxKQphbW91bnQgPC1tYXAodGFibGVfc3BsaXQsMykKaGVhZChjYXRlZ29yeSkKaGVhZChhbW91bnQpCmBgYAoKTm93IHdlIHdpbGwgY3JlYXRlIGEgYHRpYmJsZWAgdXNpbmcgdGhpcyBkYXRhLiBIb3dldmVyLCBjdXJyZW50bHkgYm90aCBgY2F0ZWdvcnlgIGFuZCBgYW1vdW50YCBhcmUgb2YgY2xhc3MgYGxpc3RgLiBUbyBjcmVhdGUgYSBgdGliYmxlYCB3ZSBuZWVkIHRvIHVubGlzdCB0aGUgZGF0YSB0byBjcmVhdGUgdmVjdG9ycy4KCmBgYHtyfQpjbGFzcyhjYXRlZ29yeSkKY2F0ZWdvcnkgJTw+JXVubGlzdCgpCmFtb3VudCAlPD4ldW5saXN0KCkKY2xhc3MoY2F0ZWdvcnkpCmBgYAoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KY2F0ZWdvcnkKYW1vdW50CmBgYAojIyMjCgpXZSBjb3VsZCBoYXZlIGRvbmUgYWxsIG9mIHRoaXMgYXQgb25jZSBpbiBvbmUgY29tbWFuZCBsaWtlIHRoaXM6CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpjYXRlZ29yeSA8LXVubGlzdChtYXAodGFibGVfc3BsaXQsMSkpCmFtb3VudCA8LXVubGlzdChtYXAodGFibGVfc3BsaXQsMykpCmBgYAoKTm93IHdlIHdpbGwgY3JlYXRlIGEgYHRpYmJsZWAsIHdoaWNoIGlzIGFuIGltcG9ydGFudCBkYXRhIGZyYW1lIHN0cnVjdHVyZSBpbiB0aGUgdGlkeXZlcnNlIHdoaWNoIGFsbG93cyB1cyB0byB1c2Ugb3RoZXIgcGFja2FnZXMgaW4gdGhlIHRpZHl2ZXJzZSB3aXRoIG91ciBkYXRhLgoKV2Ugd2lsbCBuYW1lIG91ciBgdGliYmxlYCBjb2x1bW5zIG5vdyBhcyB3ZSBjcmVhdGUgb3VyIGB0aWJibGVgIHVzaW5nIHRoZSBgdGliYmxlKClgIGZ1bmN0aW9uIG9mIGJvdGggdGhlIGB0aWR5cmAgYW5kIHRoZSBgdGliYmxlYCBwYWNrYWdlcywgYXMgbmFtZXMgYXJlIHJlcXVpcmVkIGluIHRpYmJsZXMuCgpgYGB7cn0KZ3VpZGVsaW5lcyA8LXRpYmJsZTo6dGliYmxlKGNhdGVnb3J5ID0gY2F0ZWdvcnksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFtb3VudCA9IGFtb3VudCkKZ3VpZGVsaW5lcwpgYGAKCkxvb2tpbmcgcHJldHR5IGdvb2QhCgpIb3dldmVyLCB3ZSB3YW50IHRvIHNlcGFyYXRlIHRoZSBkaWZmZXJlbnQgYW1vdW50cyB3aXRoaW4gdGhlIGFtb3VudCBjb2x1bW4uCgpSZWNhbGwgd2hhdCB0aGUgb3JnaW5hbCB0YWJsZSBsb29rZWQgbGlrZToKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjcwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgImZpcnN0cm93LnBuZyIpKQpgYGAKCiMjIyBTZXBhcmF0aW5nIHZhbHVlcyB3aXRoaW4gYSB2YXJpYWJsZQoKV2UgY2FuIHVzZSB0aGUgYHRpZHlyOjpzZXBhcmF0ZSgpYCBmdW5jdGlvbiB0byBzZXBhcmF0ZSB0aGUgZGF0YSB3aXRoaW4gdGhlIGFtb3VudCBjb2x1bW4gaW50byB0aHJlZSBuZXcgY29sdW1ucyBiYXNlZCBvbiB0aGUgb3B0aW1hbCBsZXZlbCBhbmQgdGhlIG9wdGltYWwgcmFuZ2UuIFdlIGNhbiBzZXBhcmF0ZSB0aGUgdmFsdWVzIGJhc2VkIG9uIHRoZSBvcGVuIHBhcmFudGhlc2VzIGAiKCJgIGFuZCB0aGUgbG9uZyBkYXNoIGAi4oCTImAgY2hhcmFjdGVycy4KCmBgYHtyfQojIFRoZSBmaXJzdCBjb2x1bW4gd2lsbCBiZSBjYWxsZWQgb3B0aW1hbAojIEl0IHdpbGwgY29udGFpbiB0aGUgMXN0IHBhcnQgb2YgdGhlIGFtb3VudCBjb2x1bW4gZGF0YSBiZWZvcmUgdGhlIDFzdCB1bmRlcnNjb3JlIigiCiMgVGhlIDJuZCBjb2x1bW4gd2lsbCBiZSBjYWxsZWQgbG93ZXIKIyBJdCB3aWxsIGNvbnRhaW4gdGhlIGRhdGEgYWZ0ZXIgdGhlICIoIgojIFRoZSAzcmQgY29sdW1uIHdpbGwgYmUgY2FsbGVkIHVwcGVyIAojIEl0IHdpbGwgY29udGFpbiB0aGUgMm5kIHBhcnQgb2YgdGhlIGRhdGEgYmFzZWQgb24gdGhlICLigJMiCgpndWlkZWxpbmVzJTw+JSAKICB0aWR5cjo6c2VwYXJhdGUoYW1vdW50LCAKICAgICAgICAgICAgICAgICAgYygib3B0aW1hbCIsICJsb3dlciIsICJ1cHBlciIpLAogICAgICAgICAgICAgICAgICBzZXAgPSJbWyh84oCTXV0iKSAKaGVhZChndWlkZWxpbmVzKQpgYGAKCgpMZXQncyBBbHNvIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZS9jb2x1bW4gaW4gb3VyIHRpYmJsZSB0aGF0IGluZGljYXRlcyB0aGUgZGlyZWN0aW9uIHRoYXQgY2FuIGJlIGhhcm1mdWwgZm9yIGVhY2ggZGlldGFyeSBmYWN0b3IuCgpgYGB7cn0KZ3VpZGVsaW5lcyU8PiUKICBzZXBhcmF0ZShjYXRlZ29yeSwgYygiZGlyZWN0aW9uIiwgImZvb2QiKSwgc2VwID0gIiBpbiAiKQpndWlkZWxpbmVzCmBgYAoKSWYgd2Ugd2FudGVkIHRvIHJlbW92ZSB0aGUgZGlyZWN0aW9uIHZhcmlhYmxlIHdlIGNvdWxkIHVzZSB0aGUgcHVycnI6Om1vZGlmeV9hdCgpIGZ1bmN0aW9uOgpgYGB7cixldmFsID0gRkFMU0V9Cmd1aWRlbGluZXMgJT4lIHB1cnJyOjptb2RpZnlfYXQoImRpcmVjdGlvbiIsfk5VTEwpCmBgYAoKCgoKCiMjIyBEYXRhIGNsZWFuaW5nIHdpdGggcmVndWxhciBleHByZXNzaW9ucwoKT2ssIGxvb2tpbmcgYmV0dGVyLCBidXQgd2Ugc3RpbGwgbmVlZCBhIGJpdCBvZiBjbGVhbmluZyB0byByZW1vdmUgc3ltYm9scyBhbmQgZXh0cmEgd29yZHMgZnJvbSB0aGUgY29sdW1ucy4gU29tZSBvZiB0aGUgZXh0cmEgc3ltYm9scyBpbmNsdWRlOiBgIiUiYCwgYCIpImAgYW5kIHRoZSBgIioiYC4KClRoZSBgIioiYCBhbmQgdGhlIGAiKSJgIGFyZSB3aGF0IHdlIGNhbGwgbWV0YWNoYXJhY3RlcnMgb3IgW3JlZ3VsYXIgZXhwcmVzc2lvbnNdKGh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tL3JlZ3VsYXItZXhwcmVzc2lvbnMtZXZlcnktci1wcm9ncmFtbWVyLXNob3VsZC1rbm93Lyl7dGFyZ2V0PSJfYmxhbmsifS4gVGhlc2UgYXJlIGNoYXJhY3RlcnMgdGhhdCBoYXZlIHNwZWNpYWwgbWVhbmluZ3MuCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiNzAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiUmVnRXhDaGVhdHNoZWV0LnBuZyIpKQpgYGAKCk5vdyB3ZSBuZWVkIHRoZSBgIlxcImAgdG8gaW5kaWNhdGUgdGhhdCB3ZSB3YW50IHRoZXNlIGNoYXJhY3RlcnMgdG8gYmUgbWF0Y2hlZCBleGFjdGx5IGFuZCBub3QgaW50ZXJwcmV0ZWQgYXMgdGhlIG1lYW5pbmcgb2YgdGhlIHN5bWJvbC4KClNlZSBbaGVyZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3N0cmluZ3IvdmlnbmV0dGVzL3JlZ3VsYXItZXhwcmVzc2lvbnMuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgbW9yZSBpbmZvIGFib3V0IHJlZ3VsYXIgZXhwcmVzc2lvbnMgaW4gUi4gCgpBbHNvIGhlcmUgd2UgaGF2ZSBhIGJpdCBvZiBhbiBleGFtcGxlIHVzaW5nIHRoZSBgc3RyX2NvdW50KClgIGZ1bmN0aW9uIG9mIGBzdHJpbmdyYCwgd2hpY2ggY291bnRzIHRoZSBudW1iZXIgb2YgaW5zdGVuY2VzIG9mIGEgY2hhcmFjdGVyIHN0cmluZy4gSW4gdGhpcyBjYXNlIHdlIHdpbGwgbG9vayBmb3IgaW5kaXZpZHVhbCBjaGFyYWN0ZXJzIGJ1dCB5b3UgY291bGQgYWxzbyBzZWFyY2ggZm9yIHdvcmRzIG9yIHBocmFzZXMuCgpgYGB7cn0KcmVnZXh0ZXN0PC1yZWFkcjo6cmVhZF9maWxlKGhlcmUoImRvY3MiLCAicmVnRXgudHh0IikpCnJlZ2V4dGVzdApzdHJfY291bnQocmVnZXh0ZXN0LCJ0Iikjbm90aWNlIHRoaXMgZG9lc24ndCBpbmNsdWRlIHRoZSB0IGluIHRoZSB0YWIKc3RyX2NvdW50KHJlZ2V4dGVzdCwiXHQiKSAjc2VhcmNoIGZvciB0YWIKc3RyX2NvdW50KHJlZ2V4dGVzdCwiXFx0Iikjc2VhcmNoIGZvciB0YWIKIyB0aGlzIHdpbGwgbm90IHdvcmsgYmVjYXVzZSByIHRoaW5rcyB0aGlzIGlzIHBhcnQgb2YgdGhlIGNvZGUgaXRzZWxmCiNzdHJfY291bnQocmVnZXh0ZXN0LCAiKSIpIAojIHRoaXMgd2lsbCBub3Qgd29yayBiZWNhdXNlIHIgdGhpbmtzIHRoaXMgaXMgcGFydCBvZiB0aGUgY29kZSBpdHNlbGYKI3N0cl9jb3VudChyZWdleHRlc3QsICJcKSIpCnN0cl9jb3VudChyZWdleHRlc3QsICJcXCkiKSAjdGhpcyB3b3JrcyEKIyB0aGlzIGFsc28gZG9lcyBub3Qgd29yawojc3RyX2NvdW50KHJlZ2V4dGVzdCwgIioiKQojIG5vciBkb2VzIHRoaXMKI3N0cl9jb3VudChyZWdleHRlc3QsICJcKiIpCnN0cl9jb3VudChyZWdleHRlc3QsICJcXCoiKSN0aGlzIHdvcmtzIQpgYGAKCldlIGFsc28gd2FudCB0byBtYWtlIGEgdW5pdCB2YXJpYWJsZSBzbyB0aGF0IHdlIGNhbiBtYWtlIHN1cmUgdGhhdCBvdXIgdW5pdHMgYXJlIGNvbnNpc3RlbnQgbGF0ZXIuIAoKYGBge3J9Cmd1aWRlbGluZXMgJT4lCnB1bGwob3B0aW1hbCkgCmBgYAoKTm90aWNlIHRoYXQgdGhlIHZhbHVlcyB0aGF0IGFyZSBwZXJjZW50YWdlcyBkb250IGhhdmUgc3BhY2VzIGJldHdlZW4gdGhlIG51bWJlciBhbmQgdGhlIHVuaXQuCldlIGNhbiBzZXBhcmF0ZSB0aGUgYG9wdGltYWxgIHZhbHVlcyBieSBhIHNwYWNlIG9yIGEgcGVyY2VudCBzeW1ib2wgYCIlImAgdXNpbmcgYCJ8ImAgdG8gaW5kaWNhdGUgdGhhdCB3ZSB3YW50IHRvIHNlcGFyYXRlIGJ5IGVpdGhlci4gSW4gdGhpcyBjYXNlIHdlIHdpbGwgbG9zZSB0aGUgIiUiIGFuZCB3aWxsIG5lZWQgdG8gYWRkIGl0IGJhY2sgdG8gdGhvc2UgdmFsdWVzLgoKYGBge3J9Cmd1aWRlbGluZXMlPD4lCiAgc2VwYXJhdGUob3B0aW1hbCwgaW50byA9Yygib3B0aW1hbCIsICJ1bml0IiksIHNlcCA9ICIgfCUiLCByZW1vdmUgPSBGQUxTRSkKZ3VpZGVsaW5lcwpgYGAKCkdyZWF0LCBzbyB0byBub3cgd2Ugd2lsbCBhZGQgImAlYCIgdG8gdGhlIGB1bml0YCB2YXJpYWJsZSBmb3IgIHRoZSBgbG93IGluIHBvbHl1bnNhdHVyYXRlZGAgYW5kIGBoaWdoIGluIHRyYW5zIGZhdHR5IGFjaWRzYCByb3dzLgoKRmlyc3Qgd2UgbmVlZCB0byByZXBsYWNlIHRoZSBlbXB0eSB2YWx1ZXMgd2l0aCBOQSB1c2luZyB0aGUgYG5hX2lmKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuCgpgYGB7cn0KZ3VpZGVsaW5lcyAlPD4lCm5hX2lmKCIiKQpndWlkZWxpbmVzCmBgYAoKClRoZW4gdG8gcmVwbGFjZSB0aGUgYE5BYCB2YWx1ZXMsIHdlIGNhbiB1c2UgdGhlIGByZXBsYWNlX25hKClgIGZ1bmN0aW9uIGluIHRoZSBgdGlkeXJgIHBhY2thZ2UgYW5kIHRoZSBgbXV0YXRlKClgIGZ1bmN0aW9uIG9mIGBkcGx5cmAgdG8gc3BlY2lmeSB3aGljaCB2YWx1ZXMgdG8gcmVwbGFjZSwgaW4gdGhpcyBjYXNlIHRoZSBgTkFgIHZhbHVlcyB3aXRoaW4gdGhlIHZhcmlhYmxlIGB1bml0YC4gRXNzZW50aWFsbHkgdGhpcyB2YXJpYWJsZSBnZXRzIHJlYXNpZ25lZCB3aXRoIHRoZSBuZXcgdmFsdWVzLCBhcyB3ZSBtb3N0bHkgdGhpbmsgb2YgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24gYXMgY3JlYXRpbmcgbmV3IHZhcmlhYmxlcy4KCmBgYHtyfQpndWlkZWxpbmVzICU8PiUgCiAgZHBseXI6Om11dGF0ZSh1bml0ID0gcmVwbGFjZV9uYSh1bml0LCAiJSIpKQpndWlkZWxpbmVzICU+JQogIGZpbHRlcih1bml0ID09ICIlIikKCmBgYAoKTGV0J3MgYWxzbyBtb3ZlIGB1bml0YCB0byBiZSB0aGUgbGFzdCBjb2x1bW4uIFdlIGNhbiB1c2UgdGhlIGBzZWxlY3QoKWAgYW5kIGBldmVyeXRoaW5nKClgIGZ1bmN0aW9ucyBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGRvIHRoaXMuCgpgYGB7cn0KZ3VpZGVsaW5lcyAlPD4lCiAgc2VsZWN0KC11bml0LGV2ZXJ5dGhpbmcoKSkKYGBgCgpIZXJlIHlvdSBjYW4gc2VlIEhhZGxleSBXaWNraGFtJ3MgKENoaWVmIFNjaWVudGlzdCBhdCBSU3R1ZGlvKSBleHBsYW5hdGlvbiBmb3IgdGhpcyBiZWhhdmlvciBvZiBgc2VsZWN0KClgOgoKYGBge3IsIGVjaG89IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAic2VsZWN0LnBuZyIpKQpgYGAKaHR0cHM6Ly9naXRodWIuY29tL3RpZHl2ZXJzZS9kcGx5ci9pc3N1ZXMvMjgzOCNpc3N1ZWNvbW1lbnQtMzA2MDYyODAwCgpUbyByZW1vdmUgYWxsIG9mIHRoZSByZW1haW5pbmcgZXh0cmEgY2hhcmFjdGVycyBhbmQgd29yZHMgd2Ugd2lsbCBhZ2FpbiB1c2UgdGhlIGBzdHJpbmdyYCBwYWNrYWdlLiBUaGlzIHRpbWUgd2Ugd2lsbCB1c2UgdGhlIGBzdHJfcmVtb3ZlX2FsbCgpYCBmdW5jdGlvbiB0byByZW1vdmUgYWxsIGluc3RhbmNlcyBvZiB0aGVzZSBjaGFyYWN0ZXJzLgoKYGBge3IsIGV2YWwgPSBUUlVFfQpndWlkZWxpbmVzIDwtYXNfdGliYmxlKAogIG1hcCgKICAgIGd1aWRlbGluZXMsIHN0cl9yZW1vdmVfYWxsLAogICAgcGF0dGVybiA9ICJcXCkgcGVyIGRheXxcXCkgb2YgdG90YWwgZGFpbHkgZW5lcmd5fFxcKiIpKQpgYGAKCk5pY2UhIHRoYXQncyBwcmV0dHkgY2xlYW4gYnV0IHdlIGNhbiBkbyBhIGJpdCBtb3JlLgoKIyMjIERhdGEgdHlwZSBjb252ZXJzaW9uCgpPbmUgb2YgdGhlIG5leHQgdGhpbmdzIHRvIG5vdGljZSBhYm91dCBvdXIgZGF0YSBpcyB0aGUgY2hhcmFjdGVyIGNsYXNzZXMgb2Ygb3VyIHZhcmlhYmxlcy4KCk5vdGljZSB0aGF0IHRoZSBvcHRpbWFsIGFtb3VudHMgb2YgY29uc3VtcHRpb24gYXJlIGN1cnJlbnRseSBvZiAgY2xhc3MgY2hhcmFjdGVyIGFzIGluZGljYXRlZCBieSB0aGUgYDxjaHI+YCBqdXN0IGJlbG93IHRoZSBjb2x1bW4gbmFtZXMgLyB2YXJpYWJsZSBuYW1lcyBvZiB0aGUgYGd1aWRlbGluZXNgIHRpYmJsZToKCmBgYHtyfQpndWlkZWxpbmVzCmBgYAoKClRvIGNvbnZlcnQgdGhlc2UgdmFsdWVzIHRvIG51bWVyaWMgd2UgY2FuIHVzZSB0aGUgYG11dGF0ZV9hdCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLgoKVGhlIGBtdXRhdGVfYXQoKWAgZnVuY3Rpb24gYWxsb3dzIHVzIHRvIHBlcmZvcm0gYSBmdW5jdGlvbiBvbiBzcGVjaWZpYyBjb2x1bW5zL3ZhcmlhYmxlcyB3aXRoaW4gYSB0aWJibGUuIFdlIG5lZWQgdG8gaW5kaWNhdGUgd2hpY2ggdmFyaWFibGVzIHRoYXQgd2Ugd291bGQgbGlrZSB0byBjb252ZXJ0IHVzaW5nIGB2YXJzKClgLiBJbiB0aGlzIGNhc2UgaWYgd2UgbG9vayBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBgZ3VpZGVsaW5lc2AgdGliYmxlLCB3ZSBjYW4gc2VlIHRoYXQgYG9wdGltYWxgLCBgbG93ZXJgIGFuZCBgdXBwZXJgIHNob3VsZCBiZSBjb252ZXJ0ZWQuIEFzIHRoZXNlIHRocmVlIGNvbHVtbnMgYXJlIHNlcXVlbnRpYWwsIHdlIGNhbiBzaW1wbHkgcHV0IGEgYDpgIGJldHdlZW4gYG9wdGltYWxgIGFuZCBgdXBwZXJgIHRvIGluZGljYXRlIHRoYXQgd2Ugd2FudCBhbGwgdGhlIHZhcmlhYmxlcyBpbiBiZXR3ZWVuIHRoZXNlIGNvbHVtbnMgdG8gYmUgY29udmVydGVkLiAKCmBgYHtyfQpndWlkZWxpbmVzJTw+JQogIG11dGF0ZV9hdCh2YXJzKGxvd2VyOnVwcGVyKSwgYXMubnVtZXJpYykKZ3VpZGVsaW5lcwpgYGAKCkdyZWF0ISBOb3cgdGhlc2UgdmFyaWFibGVzIGFyZSBvZiBjbGFzcyBgPGRibD5gIChzdGFuZHMgZm9yIGRvdWJsZSkgd2hpY2ggaW5kaWNhdGVzIHRoYXQgdGhleSBhcmUgbnVtZXJpYy4gSGVyZSBpcyBhIFtsaW5rXShodHRwOi8vdWMtci5naXRodWIuaW8vaW50ZWdlcl9kb3VibGUvKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGluZm8gb24gbnVtZXJpYyBjbGFzc2VzIGluIFIuCgpJZiB3ZSBoYWQgbm90IHJlcGxhY2VkIHRoZSBgIsK3ImAgaW50ZXJwdW5jdCB2YWx1ZXMgdG8gYSBwZXJpb2QgY29udmVyc2lvbiBmcm9tIGNoYXJhY3RlciB0byBudW1lcmljIHdpbGwgYmUgcHJvYmxlbWF0aWMgYW5kIHdpbGwgcmVzdWx0IGluIE5BIHZhbHVlcy4KCiMjIyBEYXRhIHZhbHVlIHJlYXNzaWdubWVudHMKCldlIHNlZW0gdG8gaGF2ZSBsb3N0IHRoZSB3b3JkIGAiYmV2ZXJhZ2VzImAgZnJvbSB0aGUgYCJzdWdhci1zd2VldGVuZWQgYmV2ZXJhZ2VzImAgY2F0ZWdvcnksICBhcyB3ZWxsIGFzIGAiZmF0dHkgYWNpZHMiYCBmcm9tIHRoZSBgInNlYWZvb2Qgb21lZ2EgMyBmYXR0eSBhY2lkcyJgLCBhbmQgdGhlIGAicG9seXVuc2F0dXJhdGVkIGZhdHR5IGFjaWRzImAgY2F0ZWdvcmllcyBhcyB0aGUgZnVsbCBjYXRlZ29yeSBuYW1lIHdhcyBsaXN0ZWQgb24gdHdvIGxpbmVzIHdpdGhpbiB0aGUgdGFibGUuIFdlIHdvdWxkIGxpa2UgdG8gcmVwbGFjZSB0aGVzZSB2YWx1ZXMgd2l0aCB0aGUgZnVsbCBuYW1lLiAKClRvIHNlbGVjdCB0aGUgYGZvb2RgIGNvbHVtbiB3ZSB3aWxsIHNob3cgeW91IHNldmVyYWwgb3B0aW9ucy4gT25seSBhIGNvdXBsZSB3aWxsIHdvcmsgd2VsbCB3aXRoIHJlYXNzaWduaW5nIHRoZSBkYXRhIGluIHRoYXQgcGFydGljdWxhciB2YXJpYWJsZSB3aXRoaW4gYGd1aWRlbGluZXNgIHdpdGhvdXQgYXNzaWduaW5nIGFuIGludGVybWVkaWF0ZSBkYXRhIG9iamVjdC4gV2Ugd2lsbCBsb29rIHVzaW5nIGBtdXRhdGVfYXQoKWAsIGBwdWxsKClgLCBgc2VsZWN0KClgLCBhbmQgYnJhY2tldHMgYFssYygidmFyaWFibGUgbmFtZSIpXWAuCgpUaGUgYnJhY2tldCBvcHRpb24gYW5kIHRoZSBzZWxlY3QoKSBvcHRpb24gd2lsbCBncmFiIGEgdGliYmxlIChkYXRhIGZyYW1lKSB2ZXJzaW9uIG9mIHRoZSBmb29kIGNvbHVtbiBvdXQgb2YgZ3VpZGVsaW5lcy4gSG93ZXZlciB3ZSBjYW4ndCBzdGFydCBjb21tYW5kcyB3aXRoIHNlbGVjdCBmb3IgYXNzaWdubWVudHMuCgpgYGB7cn0KZ3VpZGVsaW5lc1ssYygiZm9vZCIpXSAjc2FtZSBvdXRwdXQgYXMgc2VsZWN0CnNlbGVjdChndWlkZWxpbmVzLCAiZm9vZCIpICMgc2FtZSBvdXRwdXQgYXMgYnJhY2tldHMKYGBgCgoKYHB1bGwoKWAgaW4gY29udHJhc3QsIHdpbGwgZ3JhYiB0aGUgdmVjdG9yIHZlcnNpb24gb2YgdGhlIGZvb2QgZGF0YToKCmBgYHtyfQpwdWxsKGd1aWRlbGluZXMsICJmb29kIikgIyBnZXQgY2hhcmFjdGVyIHZlY3RvciBub3QgYSB0aWJibGUKYGBgCgpUaGUgcHVsbCBmdW5jdGlvbiBjYW4gYmUgdmVyeSB1c2VmdWwgd2hlbiBjb21iaW5lZCB3aXRoIG90aGVyIGZ1bmN0aW9ucyAoZm9yIGV4YW1wbGUgeW91IHR5cGljYWxseSB3YW50IHRvIHVzZSBhIHZlY3RvciB3aXRoIHRoZSBgc3RyX3JlcGxhY2UoKWAgZnVuY3Rpb24pLCBidXQganVzdCBsaWtlIHNlbGVjdCwgd2UgY2FuJ3Qgc3RhcnQgYXNzaWdubWVudHMgd2l0aCBgcHVsbCgpYC4KCgpUaGlzIGlzIG5vdCBwb3NzaWJsZSBhbmQgd2lsbCByZXN1bHQgaW4gYW4gZXJyb3I6CmBgYHtyLCBldmFsID0gRkFMU0V9CnNlbGVjdChndWlkZWxpbmVzLCBmb29kKSA8LSAKICAgc3RyX3JlcGxhY2UoIAogICBwdWxsKGd1aWRlbGluZXMsImZvb2QiKSwgCiAgIHBhdHRlcm4gPSAic3VnYXItc3dlZXRlbmVkIiwgCiAgIHJlcGxhY2VtZW50ID0gInN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMiKQpgYGAKClRoaXMgd2lsbCBvbmx5IHByaW50IHRoZSByZXN1bHQsIGJ1dCBub3QgcmVhc3NpZ24gdGhlIGZvb2QgdmFyaWFibGUgdmFsdWVzOgoKYGBge3J9Cmd1aWRlbGluZXMgJT4lCiAgIHB1bGwoZm9vZCklPiUKICAgc3RyX3JlcGxhY2UoIAogICBwYXR0ZXJuID0gInN1Z2FyLXN3ZWV0ZW5lZCIsIAogICByZXBsYWNlbWVudCA9ICJzdWdhci1zd2VldGVuZWQgYmV2ZXJhZ2VzIikKYGBgICAgCgpVc2luZyBgc2VsZWN0KClgIHdvdWxkIHdvcmsgYXMgd2VsbCB0byBwcmludCB0aGUgcmVzdWx0IChhbHRob3VnaCB0aGUgcmVzdWx0IHN0cnVjdHVyZSBpcyBkaWZmZXJlbnQpOgoKYGBge3J9Cmd1aWRlbGluZXMgJT4lCiAgIHNlbGVjdChmb29kKSU+JQogICBzdHJfcmVwbGFjZSggCiAgIHBhdHRlcm4gPSAic3VnYXItc3dlZXRlbmVkIiwgCiAgIHJlcGxhY2VtZW50ID0gInN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMiKQoKYGBgCgojIyMjIHsucXVlc3Rpb25fYmxvY2t9Cgo8dT5RdWVzdGlvbiBvcHBvcnR1bml0eTo8L3U+IAoKV2h5IGRvIHRoZXNlIGNvbW1hbmRzIG5vdCByZWFzc2lnbiB0aGUgZm9vZCB2YXJpYWJsZSB2YWx1ZXM/CgojIyMjCgpUaGUgYnJhY2tldCBvcHRpb24gaXMgZ3JlYXQgYWx0ZXJuYXRpdmUgYW5kIGFsbG93cyB1cyB0byByZWFzc2lnbiB0aGUgdmFsdWVzIHdpdGhpbiBndWlkZWxpbmVzIGVhc2lseQoKYGBge3J9CiNSZXBsYWNpbmcgInN1Z2FyLXN3ZWV0ZW5lZCIgd2l0aCAic3VnYXItc3dlZXRlbmVkIGJldmVyYWdlcyIKZ3VpZGVsaW5lc1ssYygiZm9vZCIpXSA8LSAKICBzdHJfcmVwbGFjZSggCiAgcHVsbChndWlkZWxpbmVzLCJmb29kIiksIAogIHBhdHRlcm4gPSAic3VnYXItc3dlZXRlbmVkIiwgCiAgcmVwbGFjZW1lbnQgPSAic3VnYXItc3dlZXRlbmVkIGJldmVyYWdlcyIpCgojUmVwbGFjaW5nICJzZWFmb29kIG9tZWdhLTMiIHdpdGgic2VhZm9vZCBvbWVnYS0zIGZhdHR5IGFjaWRzIgpndWlkZWxpbmVzWyxjKCJmb29kIildIDwtIAogIHN0cl9yZXBsYWNlKCAKICBwdWxsKGd1aWRlbGluZXMsImZvb2QiKSwgCiAgcGF0dGVybiA9ICJzZWFmb29kIG9tZWdhLTMiLCAKICByZXBsYWNlbWVudCA9ICJzZWFmb29kIG9tZWdhLTMgZmF0dHkgYWNpZHMiKQoKZ3VpZGVsaW5lcwpgYGAKCgpGaW5hbGx5LCB0aGUgYmVzdCBvcHRpb24gaXMgcHJvYmFibHkgdGhlIGBtdXRhdGVfYXQoKWAgZnVuY3Rpb24gZnJvbSBgZHBseXJgLiBJbiB0aGlzIGNhc2Ugd2UgbmVlZCB0byBpbmNsdWRlIGB+YCBpbiBmcm9udCBvZiB0aGUgZnVuY3Rpb24gdGhhdCB3ZSB3b3VsZCBsaWtlIHRvIHVzZSBvbiB0aGUgdmFsdWVzIGluIG91ciBgZm9vZGAgdmFyaWFibGVzLiBXZSBhbHNvIGluY2x1ZGUgYC5gIGFzIGEgcmVwbGFjZW1lbnQgdG8gcmVmZXJlbmNlIHRoZSBkYXRhIHRoYXQgd2Ugd2FudCB0byB1c2Ugd2l0aGluIGBzdHJfcmVwbGFjZSgpYCAod2hpY2ggaW4gdGhpcyBjYXNlIGlzIHRoZSBgZm9vZGAgdmFyaWFibGUgdmFsdWVzIG9mIGBndWlkZWxpbmVzYCkuCgpOb3RpY2Ugd2UgZGlkbid0IG5lZWQgdGhpcyB3aGVuIHdlIHByZXZpb3VzbHkgdXNlIGBtdXRhdGVfYXQoKWAgd2l0aCB0aGUgYGFzLm51bWVyaWMoKWAgZnVuY3Rpb24uIFRoaXMgaXMgYmVjdWFzZSB0aGUgYHN0cl9yZXBsYWNlKClgIGZ1bmN0aW9uIHJlcXVpcmVzIHVzIHRvIHNwZWNpZnkgd2hhdCBkYXRhIHdlIGFyZSB1c2luZyBhcyBvbmUgb2YgdGhlIGFyZ3VtZW50cywgd2hpbGUgYGFzLm51bWVyaWMoKWAgZG9lcyBub3QuCgpgYGB7cn0KCiNSZXBsYWNpbmcgInBvbHl1bnNhdHVyYXRlZCIgd2l0aCJwb2x5dW5zYXR1cmF0ZWQgZmF0dHkgYWNpZHMiCmd1aWRlbGluZXMlPD4lCiAgbXV0YXRlX2F0KHZhcnMoZm9vZCksCiAgfnN0cl9yZXBsYWNlKCAKICBzdHJpbmcgPSAuLCAKICBwYXR0ZXJuID0gInBvbHl1bnNhdHVyYXRlZCIsIAogIHJlcGxhY2VtZW50ID0gInBvbHl1bnNhdHVyYXRlZCBmYXR0eSBhY2lkcyIpKQoKZ3VpZGVsaW5lcwoKYGBgCgpUaGlzIG1pZ2h0IGJlIGNvbnNpZGVyZWQgYSBiZXR0ZXIgb3B0aW9uIGJlY2F1c2UgaXQgaXMgbW9yZSByZWFkaWJsZSBhcyB0byB3aGVyZSB0aGUgYGZvb2RgIGRhdGEgY2FtZSBmcm9tIHRoYXQgd2UgYXJlIHJlcGxhY2luZyB2YWx1ZXMgd2l0aGluLgoKVGhlcmUgaXMgb25lIGxhc3QgbWlub3IgZGV0YWlsLi4uIHRoZSBgZGlyZWN0aW9uYCB2YXJpYWJsZSBoYXMgbGVhZGluZyBzcGFjZXMgc3RpbGwuIFdlIGNhbiB1c2UgYHN0cl90cmltKClgIHRvIGZpeCB0aGF0IQoKYGBge3J9Cmd1aWRlbGluZXMlPD4lCiAgbXV0YXRlX2F0KHZhcnMoZGlyZWN0aW9uKSwgc3RyX3RyaW0pCgpndWlkZWxpbmVzCmBgYAoKT0shIE5vdyB3ZSBrbm93IGhvdyBtdWNoIG9mIGVhY2ggZGlldGFyeSBmYWN0b3Igd2UgZ2VuZXJhbGx5IG5lZWQgZm9yIG9wdGltYWwgaGVhbHRoIGFjY29yZGluZyB0byB0aGUgZ3VpZGVsaW5lcyB1c2VkIGluIHRoaXMgYXJ0aWNsZS4KCgpXZSB3b3VsZCBsaWtlIHRvIHNlZSBob3cgdGhlIG1lYW4gY29uc3VtcHRpb24gcmF0ZXMgZm9yIHRoZSBkaWZmZXJlbnQgZ3JvdXBzIG9mIHBlb3BsZSBjb21wYXJlZCB0byB0aGUgb3B0aW1hbCBpbnRha2UgZ3VpZGVsaW5lcy4KCk9uZSB3YXkgd2UgY291bGQgZG8gdGhpcyBpcyB0byBjYWxjdWxhdGUgYSBjb25zdW1wdGlvbiBwZXJjZW50YWdlIG9mIHRoZSBvcHRpbWFsIHZhbHVlLgoKVG8gY2FsY3VsYXRlIHRoaXMgaXQgd291bGQgYmUgaGVscGZ1bCB0byBwdXQgdGhlIGd1aWRlbGluZSBhbW91bnRzIHdpdGggdGhlIGF2ZXJhZ2UgY29uc3VtcHRpb24gcmF0ZXMgaW50byB0aGUgc2FtZSB0aWJibGUsIGVzcGVjaWFsbHkgYmVjYXVzZSB0aGUgb2JzZXJ2ZWQgY29uc3VtcHRpb24gZGF0YSAoYGRpZXRfZGF0YWAgYW5kIGBzZXBfYWdlX2RpZXRfZGF0YWApIGFyZSB2ZXJ5IGRpZmZlcmVudCBkaW1lbnNpb25zIGZyb20gdGhlIGBndWlkZWxpbmVzYCBkYXRhLiAKCkluIG9yZGVyIHRvIGNyZWF0ZSBhIHRpYmJsZSB3aXRoIG91ciBvYnNlcnZlZCBjb25zdW1wdGlvbiByYXRlcyB3aXRoIHRoZSBzdWdnZXN0ZWQgY29uc3VtcHRpb24gcmF0ZXMsIHdlIHdpbGwgam9pbiBvdXIgZGF0YSB1c2luZyBgZHBseXJgLiBJbiBvcmRlciB0byBkbyBzbyBpdCBpcyBpbXBvcnRhbnQgdGhhdCBvdXIgZGlmZmVyZW50IGRhdGFzZXRzIGhhdmUgdGhlIHNhbWUgdmFsdWVzLiBTbyBsZXQncyBmaXJzdCBhc3Nlc3MgaWYgdGhhdCBpcyB0aGUgY2FzZS4KCiMjIyBDb21wYXJpbmcgZGF0YQoKYGBge3J9CgpkaXN0aW5jdChkaWV0X2RhdGEsIHJlaV9uYW1lKQpzZWxlY3QoZ3VpZGVsaW5lcywgZm9vZCkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgd2UgbmVlZCB0byByZW1vdmUgdGhlIGAiRGlldCBsb3cgaW4iYCBhbmQgYCJEaWV0IGhpZ2ggaW4iYCBwaHJhc2VzIGZyb20gdGhlIG9ic2VydmVkIGNvbnN1bXB0aW9uIGRhdGEuCgpgYGB7cn0KZGlldF9kYXRhJHJlaV9uYW1lPC0gZGlldF9kYXRhJHJlaV9uYW1lICU+JQogIHN0cl9yZW1vdmUoIHBhdHRlcm4gPSAiRGlldCBsb3cgaW4gfERpZXQgaGlnaCBpbiAiKQoKc2VwX2FnZV9kaWV0X2RhdGEkcmVpX25hbWU8LXNlcF9hZ2VfZGlldF9kYXRhJHJlaV9uYW1lICU+JQogIHN0cl9yZW1vdmUoIHBhdHRlcm4gPSAiRGlldCBsb3cgaW4gfERpZXQgaGlnaCBpbiAiKQpgYGAKCkFsc28gbGV0J3MgZG91YmxlIGNoZWNrIHRoYXQgdGhlIHR3byBvYnNlcnZlZCBmaWxlcyBoYXZlIHRoZSBzYW1lIGV4YWN0IHZhbHVlcyBmb3IgZGlldGFyeSBmYWN0b3IgbmFtZXMuIAoKV2UgY2FuIHVzZSB0aGUgYHNldGVxdWFsKClgIGZ1bmN0aW9uIGZyb20gYGRwbHlyYCB0byBjaGVjayB0aGF0IHRoZSB1bmlxdWUgdmFsdWVzIGZvciBgcmVpX25hbWVgIGFyZSB0aGUgc2FtZSBmb3IgYm90aCBgZGlldF9kYXRhYCBhbmQgYHNlcF9hZ2VfZGlldF9kYXRhYC4KCgpgYGB7cn0Kc2V0ZXF1YWwoZGlzdGluY3QoZGlldF9kYXRhLCByZWlfbmFtZSksIAogICAgICAgICBkaXN0aW5jdChzZXBfYWdlX2RpZXRfZGF0YSwgcmVpX25hbWUpKQpgYGAKR3JlYXQhCgpOb3RlIHRoYXQgdGhlIGRlZmF1bHQgb2YgdGhlIHNldF9lcXVhbCBmdW5jdGlvbiBpZ25vcmVzIHRoZSBvcmRlciBvZiB2YWx1ZXMgaW4gcm93cy4gU28gd2Ugc3RpbGwgZG9udCBrbm93IGlmIHRoZSBvcmRlciBpcyB0aGUgc2FtZS4KCldlIGNhbiBjaGVjayB1c2luZyB0aGUgYGFsbF9lcXVhbGAgZnVuY3Rpb24gb2YgYGRwbHlyYCB3aGljaCByZXBvcnRzIGJhY2sgY2x1ZXMgYWJvdXQgd2hhdCBtaWdodCBiZSBkaWZmZXJlbnQgaWYgYW55dGhpbmcuIEltcG9ydGFudGx5IHdlIGFyZSBpbmNsdWRpbmcgYGlnbm9yZV9yb3dfb3JkZXIgPSBGQUxTRWAgYXMgdGhlIGRlZmF1bHQgaXMgYFRSVUVgLgoKYGBge3J9CmFsbF9lcXVhbChkaXN0aW5jdChkaWV0X2RhdGEsIHJlaV9uYW1lKSwgCiAgICAgICAgICBkaXN0aW5jdChzZXBfYWdlX2RpZXRfZGF0YSwgcmVpX25hbWUpLCAKICAgICAgICAgIGlnbm9yZV9yb3dfb3JkZXIgPSBGQUxTRSkKYGBgCgpMb29rcyBsaWtlIHRoZXkgYXJlIGFsc28gaW4gdGhlIHNhbWUgb3JkZXIuIAoKTm90ZSB0aGF0IGlmIGFueSBvZiB0aGUgdmFsdWVzIGFyZSBkaWZmZXJlbnQgYGFsbF9lcXVhbCgpYCB3aWxsIGZpcnN0IHJlcG9ydCB0aGlzIGFuZCB3aWxsIG5vdCByZXBvcnQgdGhhdCB0aGUgcm93cyBhcmUgaW4gYSBkaWZmZXJlbnQgb3JkZXIuCgpIZXJlIGlzIGEgdG95IGV4YW1wbGUgYWJvdXQgaG93IHRoZSB0aHJlZSBjb21wYXJpc29uIGZ1bmN0aW9ucyhgc2V0ZXF1YWwoKWAsIGBhbGxfZXF1YWwoKWAgKGFsc28gYGFsbC5lcXVhbCgpYCBmb3IgYHRibF9kZmApLCBhbmQgYHNldGRpZmYoKWApIHdvcmsgaW4gYGRwbHlyYC4gCgpJdCdzIGltcG9ydGFudCB0byByZWFsaXplIHRoYXQgcm93IG9yZGVyIGlzIGlnbm9yZWQgYnkgYm90aGBzZXRlcXVhbCgpYCBhbmQgYHNldGRpZmYoKWAuIAoKTm93IGxldCdzIGNvbXBhcmUgdHdvIHRpYmJsZXMgdGhhdCBoYXZlIGRpZmZlcmVudCByb3cgb3JkZXJzIGFuZCBkaWZmZXJudCB2YWx1ZXMuIAoKSGVyZSBhcmUgb3VyIHRpYmJsZXMgdG8gY29tcGFyZToKYGBge3J9ClggPC10aWJibGUodGVzdCA9YygiQSIsICJCIiwgIkFDIiwgIkQiKSkKWSA8LXRpYmJsZSh0ZXN0ID1jKCJBIiwgIkQiLCAiQUciLCAiQiIpKQpYClkKY2xhc3MoWSkKYGBgCgpTaW5jZSB3ZSBhcmUgdXNpbmcgdGliYmxlcywgd2hpY2ggYXJlIG9mIGNsYXNzIGB0YmxfZGZgIHdlIGNhbiB1c2UgZWl0aGVyIGBhbGxfZXF1YWxgIG9yIGBhbGwuZXF1YWwoKWAuCgpgYGB7cn0KYWxsX2VxdWFsKFgsIFksIGlnbm9yZV9yb3dfb3JkZXIgPSBUUlVFKQphbGxfZXF1YWwoWCwgWSwgaWdub3JlX3Jvd19vcmRlciA9IEZBTFNFKQojIGRvZXNudCByZXBvcnQgcm93cyBiZWluZyBkaWZmZXJlbnQgb3JkZXIKYWxsLmVxdWFsKFgsIFksIGlnbm9yZV9yb3dfb3JkZXIgPSBUUlVFKQphbGwuZXF1YWwoWCwgWSwgaWdub3JlX3Jvd19vcmRlciA9IEZBTFNFKQojIGRvZXNudCByZXBvcnQgcm93cyBiZWluZyBkaWZmZXJlbnQgb3JkZXIKCiMgUmVwb3J0cyBmYWxzZSBpbmRpY2F0aW5nIGF0IGxlYXN0IG9uZSBkaWZmZXJlbmNlCiMgRG9lcyBub3QgcHJvdmlkZSBjbHVlcyBhYm91dCB3aGF0IGlzIGRpZmZlcmVudApzZXRlcXVhbChYLCBZKQojc2V0ZGlmZigpIHRlbGxzIHVzIHdoYXQgaXMgZGlmZmVyZW50CiNzZXRkaWZmKCkgaXMgZGVwZW5kZW50IG9uIHRoZSBvcmRlciBvZiB0aGUgb2JqZWN0cyBjb21wYXJlZAojVGhpcyByZXBvcnRzIHdoYXQgaXMgdW5pcXVlIHRvIFgKc2V0ZGlmZihYLCBZKSAKI1RoaXMgcmVwb3J0cyB3aGF0IGlzIHVuaXF1ZSB0byBZCnNldGRpZmYoWSwgWCkgCmBgYAoKTm93IGxldCdzIG1ha2UgaXQgc28gdGhhdCBvbmx5IHRoZSBvcmRlciBpcyBkaWZmZXJlbnQ6CmBgYHtyfQpZIDwtdGliYmxlKHRlc3QgPWMoIkEiLCAiRCIsICJBQyIsICJCIikpClgKWQphbGxfZXF1YWwoWCwgWSwgaWdub3JlX3Jvd19vcmRlciA9IFRSVUUpCmFsbF9lcXVhbChYLCBZLCBpZ25vcmVfcm93X29yZGVyID0gRkFMU0UpIyByZXBvcnRzIGRpZmYgb3JkZXIKCiMgUmVtZW1iZXIgc2V0ZXF1YWwoKSBpZ25vcmVzIG9yZGVyIQojIEl0IHJlcG9ydHMgbm8gZGlmZmVyZW5jZSEKc2V0ZXF1YWwoWCwgWSkKIyBTZXQgZGlmZiBhbHNvIGlnbm9yZXMgb3JkZXIhCnNldGRpZmYoWCwgWSkgCmBgYAoKSWYgd2UgaGF2ZSBkaWZmZXJlbnQgY29sdW1uL3ZhcmlhYmxlIG5hbWVzIHRoaXMgbWFrZXMgY29tcGFyaXNvbnMgbW9yZSBjaGFsbGVuZ2luZzoKYGBge3J9ClggPC10aWJibGUodGVzdCA9YygiQSIsICJCIiwgIkFDIiwgIkQiKSkKWSA8LXRpYmJsZSh0ZXN0MiA9YygiQSIsICJEIiwgIkFHIiwgIkIiKSkKIyBqdXN0IHJlcG9ydHMgdGhhdCBjb2wgbmFtZXMgYXJlIGRpZmYKYWxsX2VxdWFsKFgsIFksIGlnbm9yZV9yb3dfb3JkZXIgPSBUUlVFKQojIGp1c3QgcmVwb3J0cyB0aGF0IGNvbCBuYW1lcyBhcmUgZGlmZgphbGxfZXF1YWwoWCwgWSwgaWdub3JlX3Jvd19vcmRlciA9IEZBTFNFKQpzZXRlcXVhbChYLCBZKSNUaGlzIHdvcmtzIQojc2V0ZGlmZihYLCBZKSAjIFRoaXMgd2lsbCBub3Qgd29yawpgYGAKCk9rLCBsZXQncyBrZWVwIGdvaW5nIHdpdGggb3VyIGRhdGEuCgpIb3cgc2ltaWxhciBhcmUgdGhlIGd1aWRlbGluZXMgdGliYmxlIGFuZCB0aGUgb2JzZXJ2ZWQgY29uc3VtcHRpb24gdGliYmxlcz8KCmBgYHtyfQoKc2V0ZXF1YWwoZGlzdGluY3QoZGlldF9kYXRhLCByZWlfbmFtZSksIAogICAgICAgICAgc2VsZWN0KGd1aWRlbGluZXMsIGZvb2QpKQpgYGAKCk9rLCBsb29rcyBsaWtlIHdlIGhhdmUgc29tZSBkaWZmZXJlbnQgdmFsdWVzLgoKTGV0J3MgdXNlIHRoZSBgc2V0ZGlmZmAgZnVuY3Rpb24gdG8gZ2V0IG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgd2hhdCBpcyBkaWZmZXJlbnQgYmV0d2VlbiB0aGUgdmFsdWVzLgoKYGBge3IsIGV2YWwgPSBGQUxTRX0Kc2V0ZGlmZihkaXN0aW5jdChkaWV0X2RhdGEsIHJlaV9uYW1lKSwgCiAgICAgICAgICBzZWxlY3QoZ3VpZGVsaW5lcywgZm9vZCkpCmBgYAoKOiggVGhhdCB3b250IHdvcmsuIFRoaXMgaXMgYmVjYXVzZSBgc2V0ZGlmZigpYCByZXF1aXJlcyB0aGF0IHRoZSBjb2xuYW1lcyBhcmUgdGhlIHNhbWUgaW4gdGhlIG9iamVjdHMgdGhhdCB3ZSBhcmUgY29tcGFyaW5nLgoKCldlIGNhbiB1c2UgdGhlIGByZW5hbWUoKWAgb2YgYGRwbHlyYCBmdW5jdGlvbiB0byBkbyB0aGlzLiBXZSBsaXN0IHRoZSB2YWx1ZSB0aGF0IHdlIHdhbnQgdG8gY2hhbmdlIHRvIGZpcnN0LiBXZSBmaW5kICJmb29kIiBtb3JlIGludHVpdGl2ZSBzbyB3ZSBhcmUgZ29pbmcgdG8gY2hhbmdlICJyZWlfbmFtZSIgdG8gImZvb2QiIGZvciB0aGUgYGRpZXRfZGF0YWAgYW5kIHRoZSBgc2VwX2FnZV9kaWV0X2RhdGFgCgpgYGB7cn0KZGlldF9kYXRhICU8PiUKICBkcGx5cjo6cmVuYW1lKGZvb2QgPSByZWlfbmFtZSkKc2VwX2FnZV9kaWV0X2RhdGEgJTw+JQogIGRwbHlyOjpyZW5hbWUoZm9vZCA9IHJlaV9uYW1lKQpgYGAKCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpzZXRkaWZmKGRpc3RpbmN0KGRpZXRfZGF0YSwgZm9vZCksIAogICAgICAgICAgc2VsZWN0KGd1aWRlbGluZXMsIGZvb2QpLCAKICAgICAgICAgIGlnbm9yZV9yb3dfb3JkZXIgPSBUUlVFKQpgYGAKCkdyZWF0LCBub3cgd2Uga25vdyB0aGF0IHRoZSBgZmliZXJgIHZhbHVlIGFwcGVhcnMgdG8gYmUgZGlmZmVyZW50IGJldHdlZW4gdGhlIHR3by4KCgpgYGB7cn0Kc2V0ZGlmZihzZWxlY3QoZ3VpZGVsaW5lcywgZm9vZCksCiAgICAgICAgZGlzdGluY3QoZGlldF9kYXRhLCBmb29kKSkKYGBgCgpDaGFuZ2luZyB0aGUgb3JkZXIgb2YgdGhlIG9iamVjdHMsIHdlIGNhbiBzZWUgdGhhdCBpbiB0aGUgdGFibGUgZnJvbSB0aGUgYXJ0aWNsZSB0aGF0IHdlIHVzZWQgdG8gY3JlYXRlIGd1aWRlbGluZXMsICJmaWJyZSIgdGhlIEJyaXRpc2ggc3BlbGxpbmcgaXMgdXNlZCBpbiBjb250cmFzdCB0byB0aGUgZGF0YXNldCB3aGljaCB1c2VzIHRoZSBBbWVyaWNhbiBzcGVsbGluZyAiZmliZXIiLgoKTGV0J3Mgc3RpY2sgd2l0aCB0aGUgQW1lcmljYW4gc3BlbGxpbmcsIHNvIHdlIHdpbGwgcmVwbGFjZSBgImZpYnJlImAgaW4gdGhlIGd1aWRlbGluZSB0aWJibGUuCkFnYWluLCB3ZSBoYXZlIHR3byBvcHRpb25zIGZvciBkb2luZyB0aGlzOgoKYGBge3J9CgojIGd1aWRlbGluZXNbLGMoImZvb2QiKV0gPC0gCiMgICBzdHJfcmVwbGFjZSggCiMgICBwdWxsKGd1aWRlbGluZXMsImZvb2QiKSwgCiMgICBwYXR0ZXJuID0gImZpYnJlIiwgCiMgICByZXBsYWNlbWVudCA9ICJmaWJlciIpCgpndWlkZWxpbmVzJTw+JQogIG11dGF0ZV9hdCh2YXJzKGZvb2QpLAogIH5zdHJfcmVwbGFjZSggCiAgc3RyaW5nID0gLiwgCiAgcGF0dGVybiA9ICJmaWJyZSIsIAogIHJlcGxhY2VtZW50ID0gImZpYmVyIikpCgpndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09ICJmaWJlciIpCgpgYGAKCk5vdyBsZXQncyBjaGVjayBhZ2FpbiB0byBzZWUgdGhhdCBvdXIgZm9vZCB2YWx1ZXMgbWF0Y2ggYmV0d2VlbiB0aGUgZ3VpZGVsaW5lcyBhbmQgdGhlIG9ic2VydmVkIGNvbnN1bXB0aW9uIGRhdGEgdGliYmxlcy4KCmBgYHtyfQpzZXRkaWZmKHNlbGVjdChndWlkZWxpbmVzLCBmb29kKSwKICAgICAgICBkaXN0aW5jdChkaWV0X2RhdGEsIGZvb2QpKQoKc2V0ZGlmZihzZWxlY3QoZ3VpZGVsaW5lcywgZm9vZCksCiAgICAgICAgZGlzdGluY3Qoc2VwX2FnZV9kaWV0X2RhdGEsIGZvb2QpKQpgYGAKCkdyZWF0ISAgVGhlcmUgYXJlIG5vIGRpZmZlcmVuY2VzIDopCgojIyMgSm9pbmluZyBkYXRhCgpOb3cgd2UgY2FuIHB1dCBvdXIgZ3VpZGVsaW5lIGRhdGEgdG9nZXRoZXIgd2l0aCB0aGUgYGRpZXRfZGF0YWAgYW5kIHRoZSBgc2VwX2FnZV9kaWV0X2RhdGFgLgoKUmVtZWJlciB0aGF0IHRoZSBgZm9vZGAgZGF0YSBpbiBvdXIgYGd1aWRlbGluZXNgIHRpYmJsZSBpcyBub3QgbmVjZXNzYXJpbHkgaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhhdCBvZiB0aGUgY29uc3VtcHRpb24gZGF0YSB0aWJibGVzLiBUaHVzIHRoaXMgY291bGQgYmUgYSBwcm9ibGVtIGlmIHdlIGRlY2lkZWQgdG8gZXhwYW5kIHRoZSBgZ3VpZGVsaW5lc2Agcm93cyAodG8gcmVwZWF0IGZvciB0aGUgbnVtYmVyIG9mIGZydWl0IG9ic2VydmF0aW9ucyBldGMuKSBhbmQgYWRkIHRoZW0gdG8gb3VyIG9ic2VydmVkIGNvbnN1bXB0aW9uIHRpYmJsZXMuIAoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpdGggPSAiMzAwIHB4IiwgZmlnLmFsaWduPSAiY2VudGVyIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwiYmluZC5wbmciKSkKYGBgCgpJbiB0aGF0IGNhc2Ugd2UgY291bGQgdXNlIHRoZSBgYXJyYW5nZSgpYCBmdW5jdGlvbiBvZiBgZHBseXJgIHRvIHNvcnQgdGhlIGRhdGEgYWxwaGFiZXRpY2FsbHkuCgpIb3dldmVyLCB3ZSB3aWxsIGluc3RlYWQgdXNlIGEgam9pbmluZyBmdW5jdGlvbiBvZiBgZHBseXJgLiBUaGVzZSBmdW5jdGlvbnMgY29tYmluZSB0aGUgZGF0YSB0b2dldGhlciBiYXNlZCBvbiAqKmNvbW1vbiB2YWx1ZXMqKi4gVGhlcmUgYXJlIGEgdmFyaWV0eSBvZiBvcHRpb25zLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpdGggPSAiNDAwIHB4IiwgZmlnLmFsaWduPSAiY2VudGVyIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwiam9pbi5wbmciKSkKYGBgCgpJbiBvdXIgY2FzZSB3ZSB3b3VsZCBsaWtlIHRvIHJldGFpbiBhbGwgb2YgdGhlIHZhbHVlcyBvZiBgZGlldF9kYXRhYCBhbmQgYHNlcF9hZ2VfZGlldF9kYXRhYC4gV2Ugd291bGQgbGlrZSB0byBhZGQgbmV3IGNvbHVtbnMgb2YgdmFsdWVzIHRvIHRoZXNlIHRpYmJsZXMgdGhhdCBjb3JyZXNwb25kIHRvIHRoZSBndWlkZWxpbmUgaW5mb3JtYXRpb24gYWJvdXQgYW1vdW50cyBvZiBjb25zdW1wdGlvbiBmb3IgZWFjaCBmb29kIHR5cGUgaW4gdGhlIGBndWlkZWxpbmVzYCB0aWJibGUuIFdlIHNob3VsZG4ndCBoYXZlIGFueSB2YWx1ZXMgb2YgYGZvb2RgIGluIGBndWlkZWxpbmVzYCB0aGF0IGRvbnQgbWF0Y2gsIHNvIHdlIHdpbGwgbm90IGdldCBhbnkgYE5BYCB2YWx1ZXMuIFRoZXJlZm9yZSwgaW4gb3VyIGNhc2UgYW55IG9mIHRoZSBtdXRhdGluZyBqb2luIGZ1bmN0aW9ucyBzaG91bGQgcmVzdWx0IGluIHRoZSBzYW1lIG91dHB1dC4KCgpJdCdzIGltcG9ydGFudCB0byBjaGVjayBpZiB3ZSBoYXZlIGFueSBvdmVybGFwcGluZyB2YXJpYWJsZSBuYW1lcyBiZWZvcmUgd2Ugam9pbiB0aGUgZGF0YS4gV2UgY2FuIHVzZSB0aGUgYmFzZSBSIGZ1bmN0aW9uIGBuYW1lcygpYCAgYW5kIHRoZSBgaW50ZXJzZWN0KClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgZm9yIHRoaXMuCgpgYGB7cn0KZHBseXI6OmludGVyc2VjdChuYW1lcyhkaWV0X2RhdGEpLCAKICAgICAgICAgIG5hbWVzKGd1aWRlbGluZXMpKQpgYGAKClNvIGl0IGxvb2tzIGxpa2UgdGhlIGAidXBwZXIiYCAsIGAibG93ZXIiYCBhbmQgYCJ1bml0ImAgdmFyaWFibGUgbmFtZXMgYXJlIG92ZXJsYXBwaW5nLiBUaGVyZWZvcmUsIHRvIGRpc3Rpbmd1aXNoIHRoZSBuYW1lcyBsYXRlciB3ZSB3aWxsIHJlbmFtZSB0aGUgZ3VpZGVsaW5lIGAidXBwZXIiYCAsIGAibG93ZXIiYCBhbmQgYCJ1bml0ImAgdmFyaWFibGVzLgoKV2Ugd2lsbCBhZ2FpbiB1c2UgdGhlIGByZW5hbWVgIGZ1bmN0aW9uIGZyb20gdGhlIGBkcGx5cmAgcGFja2FnZS4gV2UgY2FuIGxpc3QgbXVsdGlwbGUgdmFyaWFibGVzIHRvIHJlbmFtZSBhbmQgc2VwYXJhdGUgZWFjaCB3aXRoIGEgY29tbWEuCgpgYGB7cn0KZ3VpZGVsaW5lcyAlPD4lCiAgcmVuYW1lKHVwcGVyX29wdGltYWwgPSB1cHBlciwgCiAgICAgICAgIGxvd2VyX29wdGltYWwgPSBsb3dlciwKICAgICAgICAgIHVuaXRfb3B0aW1hbCA9IHVuaXQpCgpndWlkZWxpbmVzCmBgYAoKSXQncyBhbHNvIGEgZ29vZCBpZGVhIHRvIGNoZWNrIG91ciB1bml0cyB0byBtYWtlIHN1cmUgdGhleSBhcmUgdGhlIHNhbWUgZm9yIGJvdGggYGd1aWRlbGluZXNgIGFuZCB0aGUgb2JzZXJ2ZWQgY29uc3VtcHRpb24gdGliYmxlczogYGRpZXRfYW5kX2d1aWRlbGluZXNgIGFuZCBgYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzYC4KCkxldCdzIHRha2UgYSBsb29rIHdpdGggdGhlIGBjb3VudCgpYCBmdW5jdGlvbiBvZiBgZHBseXJgLgoKYGBge3J9CgpiaW5kX2NvbHMoZGlldGRhdGEgPSBjb3VudChkaWV0X2RhdGEsIHVuaXQsIGZvb2QpLCAKICAgICAgIHNlcGFnZWRpZXRkYXRhID0gY291bnQoc2VwX2FnZV9kaWV0X2RhdGEsdW5pdCxmb29kKSwKICAgICAgIGd1aWRlbGluZT0gY291bnQoZ3VpZGVsaW5lcywgdW5pdF9vcHRpbWFsLCBmb29kKSkKYGBgCgogV2UgY2FuIHNlZSB0aGF0IHRoZSBvbmx5IHBvdGVudGlhbCBpc3N1ZSBpcyB0aGUgYHNlYWZvb2Qgb21lZ2EtMyBmYXR0eSBhY2lkc2AgZGF0YSB3aGljaCBpcyBpbiBnL2RheSBmb3IgdGhlIG9ic2VydmVkIGRhdGEoYGRpZXRfZGF0YWAgYW5kIGBhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXNgKSwgYnV0IHRoZSB1bml0IGlzIG1nL2RheSBpbiB0aGUgYGd1aWRlbGluZXNgIGRhdGEuCgpXZSBjYW4gYWNjb3VudCBmb3IgdGhpcyBieSBkaXZpZGluZyB0aGUgZ3VpZGVsaW5lIHNlYWZvb2Qgb21lZ2EtMyBmYXR0eSBhY2lkcyBkYXRhIGJ5IDEwMDAgdG8gY29udmVydCBpdCB0byBncmFtcyBmcm9tIG1pbGxpZ3JhbXMuCgpUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgaWZfZWxzZSgpYCBmdW5jdGlvbiBpbiB0aGUgYGRwbHlyYCBwYWNrYWdlLgpUaGlzIGFsbG93cyB1cyB0byBzcGVjaWZ5IGEgY29uZGl0aW9uIChpbiB0aGlzIGNhc2UgaWYgdGhlIHVuaXQgaXMgYCJtZyJgKSwgYXMgd2VsbCBhcyB2YWx1ZXMgaWYgdGhpcyBpcyBjb2RpdGlvbiBpcyBtZXQgKHRydWUpLCBvciBpZiB0aGUgY29uZGl0aW9uIGlzIG5vdCBtZXQgKGZhbHNlKS4gSW4gdGhlIGZvbGxvd2luZyB3ZSBtdXRhdGUgdGhlIHZhbHVlcyBpbiBlYWNoIG9mIHRoZSBndWlkZWxpbmUgbnVtZXJpYyBjb2x1bW5zIChgbG93ZXJgLCBgb3B0aW1hbGAgYW5kIGB1cHBlcmApIG9uZSBhdCBhIHRpbWUuIFdoZW4gd2UgcmVmZXIgdG8gYGxvd2VyYCBmb3IgZXhhbXBsZSB3ZSByZWZlciB0byB0aGUgdmFsdWVzIGluIHRoZSBjb2x1bW4vdmFyYWlibGUuIFNvIGlmIHRoZSBjb25kaXRpb24gaXMgbm90IG1ldCwgdGhlbiB0aGUgb3JpZ2luYWwgdmFsdWUgaXMgcmV0YWluZWQuIFdlIHdpbGwgYWxzbyByZXBsYWNlIGAibWciYCB3aXRoIGAiZyJgIGFmdGVyIGV2ZXJ5dGhpbmcgaXMgY29udmVydGVkIHRvIGdyYW1zLgoKYGBge3J9Cmd1aWRlbGluZXMlPD4lIG11dGF0ZShsb3dlcl9vcHRpbWFsID0gaWZfZWxzZSgKICBjb25kaXRpb24gPSB1bml0X29wdGltYWw9PSJtZyIsIAogIHRydWUgPSBsb3dlcl9vcHRpbWFsLzEwMDAsIAogIGZhbHNlID0gbG93ZXJfb3B0aW1hbCkpCgpndWlkZWxpbmVzJTw+JSBtdXRhdGUob3B0aW1hbCA9IGlmX2Vsc2UoCiAgY29uZGl0aW9uID0gdW5pdF9vcHRpbWFsPT0ibWciLCAKICB0cnVlID0gb3B0aW1hbC8xMDAwLCAKICBmYWxzZSA9IG9wdGltYWwpKQoKZ3VpZGVsaW5lcyU8PiUgbXV0YXRlKHVwcGVyX29wdGltYWwgPSBpZl9lbHNlKAogIGNvbmRpdGlvbiA9IHVuaXRfb3B0aW1hbD09Im1nIiwgCiAgdHJ1ZSA9IHVwcGVyX29wdGltYWwvMTAwMCwgCiAgZmFsc2UgPSB1cHBlcl9vcHRpbWFsKSkKCgpndWlkZWxpbmVzJTw+JSBtdXRhdGUodW5pdF9vcHRpbWFsID0gaWZfZWxzZSgKICBjb25kaXRpb24gPSB1bml0X29wdGltYWw9PSJtZyIsIAogIHRydWUgPSAiZyIsIAogIGZhbHNlID0gdW5pdF9vcHRpbWFsKSkKCgojb3IgdGhpczoKIyBndWlkZWxpbmVzJTw+JQojICAgbXV0YXRlX2F0KHZhcnModW5pdF9vcHRpbWFsKSwKIyAgIH5zdHJfcmVwbGFjZSggCiMgICBzdHJpbmcgPSAuLCAKIyAgIHBhdHRlcm4gPSAibWciLCAKIyAgIHJlcGxhY2VtZW50ID0gImciKSkKCgpndWlkZWxpbmVzCgoKYGBgCgpUSElTIElTIFdPUksgdG8gdHJ5IHRvIG11dGF0ZSBhbGwgYXQgb25jZS4uLiBjYW4gZGVsZXRlIG9yIGtlZXAgd29ya2luZyBvbi4uLgpgYGB7cn0KI2d1aWRlbGluZXMgJT4lIG11dGF0ZV9pZihzdHJfZGV0ZWN0KGd1aWRlbGluZXMkdW5pdCwgIm1nIikgJiBpcy5udW1lcmljLCB+LisyKQojaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNTE4Nzc2MTEvY2FuLWktY29tYmluZS1hLWRwbHlyLW11dGF0ZS1hdC1tdXRhdGUtaWYtc3RhdGVtZW50CiNodHRwczovL2dpdGh1Yi5jb20vdGlkeXZlcnNlL2RwbHlyL2lzc3Vlcy82MzEKI1dPUksKI2lmIG51bWVyaWMgYW5kIHVuaXQgPSBtZz8/CiMgZ3VpZGVsaW5lcyAlPiUgCiMgICAgbXV0YXRlX2F0KGZpbHRlcihndWlkZWxpbmVzLGZvb2QgPT0gInNlYWZvb2Qgb21lZ2EtMyBmYXR0eSBhY2lkcyIpLHZhcnMobG93ZXI6dXBwZXIpLCBmdW5zKC4vMTAwMCkpCiMgCiMgZ3VpZGVsaW5lcyAlPiUgCiMgICAgaWZfZWxzZSh1bml0ID09ICJtZyIsIG11dGF0ZV9hdChsaXN0KGxvd2VyOnVwcGVyKSxpZl9lbHNlKHVuaXQgPT0gIm1nIiwgdHJ1ZSA9IGZ1bnMoLi8xMDAwKSwgZmFsc2UgPSAuKSkpCiAjIG11dGF0ZV9hdChmaWx0ZXIoZ3VpZGVsaW5lcyxmb29kID09ICJzZWFmb29kIG9tZWdhLTMgZmF0dHkgI2FjaWRzIiksdmFycyhsb3dlcjp1cHBlciksIGZ1bnMoLi8xMDAwKSkKIyBndWlkZWxpbmVzICU+JSAKIyAgICBmaWx0ZXIoZm9vZCA9PSAic2VhZm9vZCBvbWVnYS0zIGZhdHR5IGFjaWRzIiklPiUKIyAgICBtdXRhdGVfYXQodmFycyhsb3dlcjp1cHBlciksIGZ1bnMoLi8xMDAwKSkKIyAKIyBndWlkZWxpbmVzICU+JSAKIyAgICBpZl9lbHNlKHVuaXQgPT0gIm1nIiwgbXV0YXRlX2F0KGxpc3QobG93ZXI6dXBwZXIpLGlmX2Vsc2UodW5pdCA9PSAibWciLCB0cnVlID0gZnVucyguLzEwMDApLCBmYWxzZSA9IC4pKSkKIyBndWlkZWxpbmVzJT4lCiMgICBtdXRhdGVfYXQodmFycyhsb3dlcjp1cHBlciksIGZ1bnMoaWZlbHNlKHVuaXQ9PSJtZyIsIFRSVUUvMTAwMCwgVFJVRSkpKQojIAojIAojIG11dGF0ZShjYXJzLCBkaXN0ID0gaWZlbHNlKHNwZWVkPT00LCBkaXN0KjEwMCwgZGlzdCkpCiMgCiMgCiMgZ3VpZGVsaW5lc1tjKCJzZWFmb29kIG9tZWdhLTMgZmF0dHkgYWNpZHMiKSxdIAojIGd1aWRlbGluZXNbYygic2VhZm9vZCBvbWVnYS0zIGZhdHR5IGFjaWRzIiksXSAgPC1ndWlkZWxpbmVzICU+JSAKIyAgIGZpbHRlcihmb29kID09ICJzZWFmb29kIG9tZWdhLTMgZmF0dHkgYWNpZHMiKSU+JQojICAgbXV0YXRlX2F0KHZhcnMobG93ZXI6dXBwZXIpLCBmdW5zKDEwKi4pKQojIAojIGNhcnM8LW11dGF0ZShjYXJzLCBkaXN0MiA9IGRpc3QpCiMgbXV0YXRlKGNhcnMsIGRpc3QgPSBpZmVsc2Uoc3BlZWQ9PTQsIGRpc3QqMTAwLCBkaXN0KSkKCmd1aWRlbGluZXMgJT4lIAogICAgZmlsdGVyKGZvb2QgPT0gInNlYWZvb2Qgb21lZ2EtMyBmYXR0eSBhY2lkcyIpJT4lCiAgICBtdXRhdGVfYXQodmFycyhsb3dlcl9vcHRpbWFsOnVwcGVyX29wdGltYWwpLCBmdW5zKC4vMTAwMCkpCgoKCgojIHR5cGUgPC0gYygxOjQpCiMgeWVhcjEgPC0gYygxOjQpCiMgeWVhcjIgPC0gYygxOjQpCiMgeWVhcjMgPC0gYygxOjQpCiMgZGF0YSA8LSBkYXRhLmZyYW1lKHR5cGUsIHllYXIxLCB5ZWFyMiwgeWVhcjMpCiMgCiMgCiMgbmV3ZGF0YSA8LSBkYXRhICU+JQojICAgZ2F0aGVyKC4sIHllYXIsIHZhbHVlLCB5ZWFyMTp5ZWFyMykgJT4lCiMgICBtdXRhdGUobmV3dmFsdWUgPSBpZmVsc2UodHlwZSA+IDIsIHZhbHVlICogMiwgdmFsdWUpKSAlPiUKIyAgIHNlbGVjdCgtdmFsdWUpICU+JQojICAgc3ByZWFkKC4sIHllYXIsIG5ld3ZhbHVlKQojIAojIERmICU+JSAKIyAgIG11dGF0ZV9hbGwoCiMgICAgIGZ1bnMoY2FzZV93aGVuKAojICAgICAuID09ICIxIiAgfiAxKi4sCiMgICAgIC4gPT0gIjIiICB+IDIqLiwKIyAgICAgLiA9PSAiMyIgIH4gMyouKSkpICU+JQojIG11dGF0ZShyb3dtYXggPSBwbWF4KCEhIXJsYW5nOjpzeW1zKG5hbWVzKC4pKSkpCiMgCiMgZGYgJT4lIG11dGF0ZV9hdCh2YXJzKGE6YyksIGZ1bnMoaWZlbHNlKGlzLm5hKGQpIHwgZCA9PSAwLCBOQSwgLikpKQojIAojIAojIAojIG1zbGVlcCAlPiUKIyAgIHNlbGVjdChuYW1lLCBzbGVlcF90b3RhbCkgJT4lCiMgICBtdXRhdGUoc2xlZXBfdG90YWxfbWluID0gc2xlZXBfdG90YWwgKiA2MCkKCmBgYAoKCk5vdyB3ZSBhcmUgcmVhZHkgdG8gam9pbiB0aGUgZGF0YSEKCkFnaWFuLCB3ZSB3b3VsZCBsaWtlIHRvIGFkZCBuZXcgY29sdW1ucyBvZiB2YWx1ZXMgdG8gYGRpZXRfZGF0YWAgYW5kIGBhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXNgIHRoYXQgY29ycmVzcG9uZCB0byB0aGUgZ3VpZGVsaW5lIGluZm9ybWF0aW9uIGFib3V0IGFtb3VudHMgb2YgY29uc3VtcHRpb24gZm9yIGVhY2ggZm9vZCB0eXBlIGluIHRoZSBgZ3VpZGVsaW5lc2AgdGliYmxlLiBTbyB3ZSB3aWxsIGpvaW4gdGhlIGRhdGEgYmFzZWQgb24gdGhlIGBmb29kYCB2YXJpYWJsZSB2YWx1ZXMuCgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyA8LWRpZXRfZGF0YSAlPiUKICBmdWxsX2pvaW4oZ3VpZGVsaW5lcywgYnkgPSAiZm9vZCIgKQoKYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzIDwtc2VwX2FnZV9kaWV0X2RhdGEgJT4lCiAgZnVsbF9qb2luKGd1aWRlbGluZXMsIGJ5ID0gImZvb2QiICkKCmdsaW1wc2UoZGlldF9hbmRfZ3VpZGVsaW5lcykKZ2xpbXBzZShhbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMpCgpgYGAKCkl0J3MgYWx3YXlzIGEgZ29vZCBpZGVhIHRvIGNoZWNrIHRoYXQgdGhlIHZhbHVlcyBhcmUgd2hhdCB5b3UgZXhwZWN0IGFmdGVyIG1lcmdpbmcuIAoKYGBge3J9CgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGNvdW50KGZvb2QsIG9wdGltYWwpCgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgY291bnQoZm9vZCwgb3B0aW1hbCkKCmd1aWRlbGluZXMKYGBgCiBMb29rcyBnb29kIQogCiAKIyMjIENhbGN1bGF0ZSByZWxhdGl2ZSBjb25zdW1wdGlvbiAKCkFnYWluLCB3ZSB3b3VsZCBsaWtlIHRvIGNvbXBhcmUgdGhlIGNvbnN1bXB0aW9uIHJhdGVzIG9mIHRoaXMgZGlldGFyeSBmYWN0b3JzIGJ5IGRpZmZlcmVudCBncm91cHMgb2YgcGVvcGxlLCBidXQgaWRlYWxseSB3ZSB3YW50IHRvIGtub3cgdGhpcyByZWxhdGl2ZSB0byB0aGUgb3B0aW1hbCBndWlkZWxpbmVzLgoKVGh1cyBsZXRzIGNhbGN1YXRlIHZhbHVlcyBvZiBjb25zdXB0aW9uIHRoYXQgYXJlIHJlbGF0aXZlIHRvIHRoZSBzdWdnZXN0ZWQgZ3VpZGVsaW5lcy4KClRoZXJlIGFyZSBhIGZldyB3YXlzIHdlIGNvdWxkIGRvIHRoaXMuIE9uZSBpcyB0byBjYWxjdWxhdGUgYSBwZXJjZW50YWdlIG9mIGNvbnN1bXB0aW9uIGJhc2VkIG9uIHRoZSBtZWFuIHZhbHVlIGZvciBlYWNoIG9ic2VydmVkIHZhbHVlIHJlbGF0aXZlIHRvIHRoZSBvcHRpbWFsIHZhbHVlLiBUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgbXV0YXRlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgcGFja2FnZS4gVGhpcyB3aWxsIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgYG1lYW5fcGVyY2VudGAgdGhhdCB3aWxsIGJlIGVxdWFsIHRvIHRoZSBkaXZpc2lvbiByZXN1bHQgb2YgdGhlIGBtZWFuYCB2YXJpYWJsZSB2YWx1ZSBhbmQgdGhlIGBvcHRpbWFsYCB2YXJpYWJsZSBtdWx0aXBsaWVkIGJ5IDEwMCB0byBjcmVhdGUgYSBwZXJjZW50YWdlLgoKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJTw+JQogIG11dGF0ZShtZWFuX3BlcmNlbnQgPSAobWVhbi9vcHRpbWFsKSoxMDApCgphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXMgJTw+JQogbXV0YXRlKG1lYW5fcGVyY2VudCA9IChtZWFuL29wdGltYWwpKjEwMCkKYGBgCgpBbm90aGVyIG9wdGlvbiBpcyB0byBpbmNvcnBlcmF0ZSB0aGUgcmFuZ2Ugb2Ygb3B0aW1hbCBpbnRha2VzIGFuZCB0aGUgZGlyZWN0aW9uIHRoYXQgaXMgYXNzb2NpYXRlZCB3aXRoIGhlYWx0aCByaXNrLiBJZiB0aGUgZGlyZWN0aW9uIG9mIHJpc2sgaXMgYGhpZ2hgIGFuZCB0aGUgY29uc3VtcHRpb24gd2FzIGdyZWF0ZXIgdGhhbiB0aGUgYG9wdGltYWxgIG1lYW4gdmFsdWUsIHRoYW4gdGhlIHBlcmNlbnRhZ2UgaXMgY2FsY3VsYXRlZCBiYXNlZCBvbiB0aGUgYHVwcGVyX29wdGltYWxgIHZhbHVlLCB3aGlsZSBpZiB0aGUgZGlyZWN0aW9uIG9mIHJpc2sgaXMgYGxvd2AgYW5kIHRoZSBjb25zdW1wdGlvbiBpcyBsZXNzIHRoYW4gdGhlIG9wdGltYWwgbWVhbiB2YWx1ZSwgdGhlbiB0aGUgcGVyY2VudGFnZSBpcyBjYWxjdWxhdGVkIGJhc2VkIG9uIHRoZSBgbG93ZXJfb3B0aW1hbGAgdmFsdWUuIFdlIHdpbGwgdXNlIHRoZSBgY2FzZV93aGVuKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gZG8gdGhpcy4gVGhpcyBhbGxvd3MgdXMgdG8gc3BlY2lmeSB2YWx1ZXMgKGluZGljYXRlZCBvbiB0aGUgcmlnaHQgc2lkZSBvZiB0aGUgYH5gc3ltYm9sKSBiYXNlZCBvbiBzcGVjaWZpYyBjb25kaXRpb25zIChpbmRpY2F0ZWQgb24gdGhlIGxlZnQgc2lkZSBvZiB0aGUgYH5gIHN5bWJvbCkuIFdlIGNhbiBzcGVjaWZ5IG11bHRpcGxlIGNvbmRpdGlvbnMgdXNpbmcgdGhlIGAmYCBzeW1ib2wuCgpgYGB7cn0KCmRpZXRfYW5kX2d1aWRlbGluZXMgJTw+JQogIG11dGF0ZShyYW5nZV9wZXJjZW50ID1jYXNlX3doZW4oCiAgZGlyZWN0aW9uID09ICJoaWdoIiB+ICAobWVhbi91cHBlcl9vcHRpbWFsKSoxMDAsCiAgZGlyZWN0aW9uID09ICJsb3ciICB+ICAobWVhbi9sb3dlcl9vcHRpbWFsKSoxMDApKQoKYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU8PiUKICBtdXRhdGUocmFuZ2VfcGVyY2VudCA9Y2FzZV93aGVuKAogIGRpcmVjdGlvbiA9PSAiaGlnaCIgfiAgKG1lYW4vdXBwZXJfb3B0aW1hbCkqMTAwLAogIGRpcmVjdGlvbiA9PSAibG93IiAgfiAgKG1lYW4vbG93ZXJfb3B0aW1hbCkqMTAwKSkKCgpkaWV0X2FuZF9ndWlkZWxpbmVzICU8PiUKICBtdXRhdGUocGVyY2VudF9vdmVyX3VuZGVyID1jYXNlX3doZW4oCiAgZGlyZWN0aW9uID09ICJoaWdoIiAmIG1lYW4+dXBwZXJfb3B0aW1hbCB+ICAoKG1lYW4tdXBwZXJfb3B0aW1hbCkvdXBwZXJfb3B0aW1hbCkqMTAwLAogIGRpcmVjdGlvbiA9PSAiaGlnaCIgJiBtZWFuPD11cHBlcl9vcHRpbWFsIH4gMCwKICBkaXJlY3Rpb24gPT0gImxvdyIgICYgbWVhbj49bG93ZXJfb3B0aW1hbCB+IDAsCiAgZGlyZWN0aW9uID09ICJsb3ciICAmIG1lYW48bG93ZXJfb3B0aW1hbCB+ICgobG93ZXJfb3B0aW1hbC1tZWFuKS9sb3dlcl9vcHRpbWFsKSoxMDApKQoKCmFsbF9hZ2VfZGlldF9hbmRfZ3VpZGVsaW5lcyAlPD4lCiAgbXV0YXRlKHBlcmNlbnRfb3Zlcl91bmRlciA9Y2FzZV93aGVuKAogIGRpcmVjdGlvbiA9PSAiaGlnaCIgJiBtZWFuPnVwcGVyX29wdGltYWwgfiAgKChtZWFuLXVwcGVyX29wdGltYWwpL3VwcGVyX29wdGltYWwpKjEwMCwKICBkaXJlY3Rpb24gPT0gImhpZ2giICYgbWVhbjw9dXBwZXJfb3B0aW1hbCB+IDAsCiAgZGlyZWN0aW9uID09ICJsb3ciICAmIG1lYW4+PWxvd2VyX29wdGltYWwgfiAwLAogIGRpcmVjdGlvbiA9PSAibG93IiAgJiBtZWFuPGxvd2VyX29wdGltYWwgfiAoKGxvd2VyX29wdGltYWwtbWVhbikvbG93ZXJfb3B0aW1hbCkqMTAwKSkKCmBgYAoKWWV0IGFub3RoZXIgb3B0aW9uIGlzIHRvIGNyZWF0ZSBhIGJpbmFyeSBvdXRjb21lIG9mIGlmIG9wdGltYWwgY29uc3VtcHRpb24gd2FzIGFjaGlldmVkIG9yIG5vdC4KCmBgYHtyfQoKZGlldF9hbmRfZ3VpZGVsaW5lcyAlPD4lCiAgbXV0YXRlKG9wdF9hY2hpZXZlZCA9IGlmX2Vsc2UoCiAgICBjb25kaXRpb24gPSBkaXJlY3Rpb24gPT0ibG93IiAmIG1lYW4gPiBsb3dlcl9vcHRpbWFsIHwKICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9PSAiaGlnaCIgJiBtZWFuIDwgdXBwZXJfb3B0aW1hbCwgCiAgICB0cnVlID0gIlllcyIsCiAgICBmYWxzZSA9ICJObyIpKQoKYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU8PiUKICBtdXRhdGUob3B0X2FjaGlldmVkID0gaWZfZWxzZSgKICAgIGNvbmRpdGlvbiA9IGRpcmVjdGlvbiA9PSJsb3ciICYgbWVhbiA+IGxvd2VyX29wdGltYWwgfAogICAgICAgICAgICAgICAgZGlyZWN0aW9uID09ICJoaWdoIiAmIG1lYW4gPCB1cHBlcl9vcHRpbWFsLCAKICAgIHRydWUgPSAiWWVzIiwKICAgIGZhbHNlID0gIk5vIikpCgpnbGltcHNlKGRpZXRfYW5kX2d1aWRlbGluZXMpCmdsaW1wc2UoYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzKQpgYGAKCk9uZSBsYXN0IHRoaW5nIHRoYXQgY2FuIGJlIHVzZWZ1bCB3aXRoIGRhdGEgd3JhbmdsaW5nIGlzIHRvICoqcmVzaGFwZSoqIHRoZSBkYXRhIGludG8gd2hhdCBpcyBjYWxsZWQgdGhlICoqbG9uZyoqIGZvcm1hdC4gVGhpcyBpcyB2ZXJ5IHVzZWZ1bCBmb3IgY3JlYXRpbmcgdmlzdWFsaXphdGlvbnMgd2l0aCBhIHZlcnkgdXNlZnVsIHBhY2thZ2UgY2FsbGVkIGBnZ3Bsb3QyYC4KClRvIGNvZXJjZSBhbiBvYmplY3QgaW50byBsb25nIGZvcm1hdCwgd2UgY3JlYXRlIG1vcmUgcm93cyBhbmQgZmV3ZXIgY29sdW1ucy4gRm9yIGEgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGlzLCBwbGVhc2Ugc2VlIHRoaXMgW2Nhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtaGVhbHRoZXhwZW5kaXR1cmUvb2NzLWhlYWx0aGV4cGVuZGl0dXJlLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uCgpXZSB3b3VsZCBsaWtlIHRvIHB1dCB0b2V0aGVyIHRoZSBkaWZmZXJlbnQgdHlwZXMgb2YgcGVyY2VudGFnZXMgb2YgdGhlIG9wdGltYWwgaW50YWtlIHRoYXQgd2UganVzdCBjYWxjdWxhdGVkLgoKVG8gZ2V0IG91ciBkYXRhIGluIGxvbmcgZm9ybWF0IHdlIGNhbiB1c2UgdGhlIGBwaXZvdF9sb25nZXIoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gV2Ugd2lsbCBhbHNvIHNob3cgaG93IHRoaXMgd291bGQgYmUgZG9uZSB3aXRoIHRoZSBvbGRlciB2ZXJzaW9uIG9mIHRoaXMgZnVuY3Rpb24sIGNhbGxlZCBgZ2F0aGVyKClgLiAKCkZvciBgcGl2b3RfbG9uZ2VyKClgLCB3ZSB3aWxsIGxpc3QgdGhlIGNvbHVtbnMgdGhhdCB3ZSB3YW50IHRvIGNvbWUgdG9nZXRoZXIgaW50byB0aGUgbG9uZ2VyIGZvcm1hdCB1c2luZyB0aGUgYGNvbHNgIGFyZ3VtZW50LiBGb3IgYGdhdGhlcigpYCB3ZSB3b3VsZCBzaW1wbHkgbGlzdCB0aGUgdmFyaWFibGVzIHRoYXQgd2Ugd2lzaCB0byBjb25zb2xpZGF0ZS4gVGhlIGBuYW1lc190b2AgYXJndW1lbnQgaW5kaWNhdGVzIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSB0aGF0IHdpbGwgaW5jbHVkZSB0aGUgY2hhcmFjdGVyIGluZm9ybWF0aW9uIGFib3V0IHRoZSB2YWx1ZXMgdGhhdCB3ZSBhcmUgY29uc29saWRhdGluZywgdGhpcyBpcyB0aGUgdmFyaWFibGUgbmFtZXMgb2YgdGhlIGNvbHVtbnMgdGhhdCB3ZSBhcmUgYnJpbmdpbmcgdG9nZXRoZXIuIFRoaXMgaXMgZXF1aXZhbGVudCB0byB0aGUgYGtleWAgYXJlZ3VtZW50IGluIGBnYXRoZXIoKWAuIFRoZSBgdmFsdWVzX3RvYCBpcyB0aGUgbmFtZSBvZiB0aGUgY29sdW1uIHRoYXQgd2lsbCBjb250YWluIHRoZSB2YWx1ZXMgb2YgdGVoIGNvbHVtbnMgd2UgYXJlIGNvbnNvbGlkYXRpbmcuIFRoaXMgaXMgZXF1aXZhbGVudCB0byB0aGUgYHZhbHVlYCBhcmVndW1lbnQgaW4gYGdhdGhlcigpYC4gV2UgY2FuIHVzZSBgY29udGFpbnMoKWAgb2YgdGhlIGB0aWR5cmAgcGFja2FnZSB0byBsb29rIGF0IHRoZSB2YXJpYWJsZXMgd2l0aCBuYW1lcyB0aGF0IGNvbnRhaW4gYCJwZXJjZW50ImAgLgoKV2Ugd291bGQgZ2V0IGFuIGlkZW50aWNhbCBvdXRwdXQgZnJvbSB0aGUgbWV0aG9kcy4KCmBgYHtyfQpkaWV0X2FuZF9ndWlkZWxpbmVzX2xvbmc8LWRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCnBpdm90X2xvbmdlcihjb2xzID0gY29udGFpbnMoInBlcmNlbnQiKSwgCiAgICAgICAgICAgICBuYW1lc190byA9ICJwZXJjZW50X3R5cGUiLCAKICAgICAgICAgICAgIHZhbHVlc190byA9ICJwZXJjZW50IikKCmRpZXRfYW5kX2d1aWRlbGluZXNfbG9uZzI8LWRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCmdhdGhlcihjb250YWlucygicGVyY2VudCIpLAogICAgICAga2V5ID0gcGVyY2VudF90eXBlLCAKICAgICAgIHZhbHVlID0gcGVyY2VudCkKCnNldGVxdWFsKGRpZXRfYW5kX2d1aWRlbGluZXNfbG9uZywgZGlldF9hbmRfZ3VpZGVsaW5lc19sb25nMikKYGBgCgpMZXQncyBkbyB0aGUgc2FtZSBmb3IgdGhlIGFnZSBzZXBhcmF0ZWQgZGF0YS4KCmBgYHtyfQphbGxfYWdlX2RpZXRfYW5kX2d1aWRlbGluZXNfbG9uZzwtYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU+JQpwaXZvdF9sb25nZXIoY29scyA9IGNvbnRhaW5zKCJwZXJjZW50IiksIAogICAgICAgICAgICAgbmFtZXNfdG8gPSAicGVyY2VudF90eXBlIiwgCiAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAicGVyY2VudCIpCmBgYAoKIyMgRGF0YSBFeHBsb3JhdGlvbgogCiMjIyBFeHBsb3JpbmcgYWdlIGNvbGxhcHNlZCBkYXRhCgpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgIHBlcmNlbnQgb2YgY29uc3VtcHRpb24uIEFnYWluIHdlIHdpbGwgdXNlIHRoZSBiYXNlIFIgYHN1bW1hcnkoKWAgZnVuY3Rpb246CgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBzZWxlY3QobWVhbl9wZXJjZW50KSU+JQogIHN1bW1hcnkoKQpgYGAKCldvdyEgU29tZSBvZiB0aGUgdmFsdWVzIGFyZSBuZWFybHkgemVybywgc3VnZ2VzdGluZyB0aGF0IHNvbWUgcGVvcGxlIGFyZSBjb25zdW1pbmcgYmFzaWNhbGx5IHplcm8gcGVyY2VudCBvZiB3aGF0IGlzIHN1Z2dlc3RlZCBmb3Igb3B0aW1hbCBoZWFsdGguIE9uIHRoZSBvdGhlciBoYW5kLCBmb3Igc29tZSBkaWV0YXJ5IGZhY3RvcnMgcGVvcGxlIGFyZSBjb25zdW1pbmcgb3ZlciA3LDAwMCBwZXJjZW50IHdoYXQgaXMgc3VnZ2VzdGVkISAKClRoaXMgaXMgd2h5IGl0IGlzIGltcG9ydGFudCB0byBsb29rIGF0IHRoZSBkaXJlY3Rpb24gb2YgY29uc3VtcHRpb24gdGhhdCBjb3VsZCBiZSBoYXJtZnVsLiBGb3IgZXhhbXBsZSBpZiB0aGVyZSBpcyBhIHBvcHVsYXRpb24gdGhhdCBjb25zdW1lcyBsYXJnZSBhbW91bnRzIG9mIHZlZ2F0YWJsZXMgdGhpcyBjb3VsZCBiZSBhIGdvb2QgdGhpbmcsIGJ1dCBpZiB0aGVyZSBpcyBhIHBvcHVsYXRpb24gY29uc3VtaW5nIGxhcmdlIGFtb3VudHMgb2Ygc29kaXVtIHRoaXMgd291bGQgYmUgYSBiYWQgdGhpbmcuIAoKTGV0J3MgdGFrZSBhIGxvb2sgdG8gc2VlIHdoYXQgZGlldGFyeSBmYWN0b3JzIGFyZSBhdCB0aGUgZXh0cmVtZXMgYnkgYXJyYW5naW5nIHRoZSBkYXRhIHVzaW5nIHRoZSBgYXJyYW5nZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBXZSBjYW4gYXJyYW5nZSBieSBzbWFsbGVzdCB0byBsYXJnZXN0IHVzaW5nIHRoZSBkZWZhdWx0IGFuZCB3ZSBjYW4gYXJyYW5nZSBsYXJnZXN0IHRvIHNtYWxsZXN0IHVzaW5nIHRoZSBtaW51cyBzaWduIGAtYC4KCmBgYHtyfQoKZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBhcnJhbmdlKC1tZWFuX3BlcmNlbnQpJT4lCiAgZ2xpbXBzZSgpCgpgYGAKCk9rLCBzbyBpdCBsb29rcyBsaWtlIHN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMgYXJlIHJlYWxseSBvdmVyY29uc3VtZWQgaW4gc29tZSBwYXJ0cyBvZiB0aGUgd29ybGQhCgpSZWNhbGwgZnJvbSB0aGUgc3VwcGxlbWVudGFyeSB0YWJsZSBmcm9tIHRoZSBhcnRpY2xlIHRoYXQgb3ZlcmNvbnN1bXB0aW9uIG9mIHN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMgaXMgYXNzb2NpYXRlZCB3aXRoIGJvdGggRGlhYmV0ZXMgbWVsbGl0dXMgdHlwZSAyIGFuZCBJc2NoZW1pYyBoZWFydCBkaXNlYXNlLiBUaGlzIFthcnRpY2xlXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM1MTMzMDg0Lyl7dGFyZ2V0PSJfYmxhbmsifSBkaXNjdXNzZXMgc29tZSBvZiB0aGUgY29udHJldnN5IG92ZXIgdGhlIHBvdGVudGlhbCBoZWFsdGggcmlza3MgYXNzb2NpYXRlZCB3aXRoIGhpZ2ggY29uc3VtcHRpb24gb2Ygc3VnYXIuCgpJdCBzdGlsbCBsb29rcyBxdWl0ZSBiYWQgaWYgd2UgbG9vayBhdCB0aGUgb3RoZXIgY2FsY3VsYXRlZCBwZXJjZW50YWdlIHZhbHVlcy4gCmBgYHtyfQpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogICBzZWxlY3QoY29udGFpbnMoInBlcmNlbnQiKSklPiUKICAgc3VtbWFyeSgpCmBgYApTbyBzb21lIHBsYWNlcyBhcmUgc3RpbGwgY29uc3VtaW5nIDQsMDAwIHBlcmNlbnQgbW9yZSB0aGFuIHRoZSB1cHBlciByYW5nZSBvZiB0aGUgc3VnZ2VzdGVkIG9wdGltYWwgaW50YWtlLgoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgZ2xvYmFsIGxldmVsczoKYGBge3J9CgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09InN1Z2FyLXN3ZWV0ZW5lZCBiZXZlcmFnZXMiICYgbG9jYXRpb25fbmFtZSA9PSJHbG9iYWwiKQoKYGBgCgpGb3IgdGhvc2Ugd2hvIGFyZSBsZXNzIGZhbWlsaWFyIHdpdGggdGhlIG1ldHJpYyBzeXN0ZW0gd2hlcmUgZ3JhbXMgYXJlIGVxdWl2YWxlbnQgdG8gbWlsbGlsaXRlcnMsIGl0IG1heSBiZSB1c2VmdWwgdG8gcmVhbGl6ZSBob3cgbWFueSBmbHVpZCBvdW5jZXMgdGhlIG1heCBhbW91bnQgb2YgY29uc3VtcHRpb24gcGVyIGRheSAofjI0OCkgZ3JhbXMgYWN0YXVsbHkgaXMuIAoKVGhlcmUgYXJlIDAuMzUyNDcgb3VuY2VzIGluIG9uZSBncmFtLgoKYGBge3J9CiN0b3AgYW1vdW50IGluIG91bmNlcwowLjM1MjQ3KjI0Ny45MzQyIApgYGAKCk9rLCBzbyB0aGUgdG9wIGNvbnN1bWVycyBhcmUgZHJpbmtpbmcgYWJvdXQgODcgZmx1aWQgb3VuY2VzIHBlciBkYXkuIFNpbmNlIHRoZXJlIGFyZSAxMiBvdW5jZXMgaW4gYSBzaW5nbGUgY2FuIG9mIHNvZGEsIHRoaXMgaXMgYWJvdXQgYHIgODcvMTJgIHNvZGFzIHBlciBkYXkuIEdsb2JhbGx5IG9uIGF2ZXJhZ2UsIG1hbGVzIGFyZSBkcmlua2luZyBgciAoNjUuNSowLjM1MjQ3KS8xMmAgYWJvdXQgc29kYXMgd29ydGggb2Ygc3dlZXRlbmVkIGJldmVyYWdlcywgd2hpbGUgZmVtYWxlcyBhcmUgZHJpbmtpbmcgYWJvdXQgYHIgKDQ3LjcqMC4zNTI0NykvMTJgLgoKCkxldCdzIHRha2UgYSBsb29rIGF0IHdoYXQgaXMgdW5kZXJjb25zdW1lZDoKCmBgYHtyfQoKZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBhcnJhbmdlKG1lYW5fcGVyY2VudCklPiUKICBnbGltcHNlKCkKCiNnbGltcHNlKGZpbHRlcihkaWV0X2FuZF9ndWlkZWxpbmVzLCBsb2NhdGlvbl9uYW1lID09ICJMYW9zIiwgbWVhbj4yMDApKQpgYGAKCk9uIHRoZSBvdGhlcmhhbmQsIGl0IGxvb2tzIGxpa2Ugc29tZSBwbGFjZXMgYXJlIGNvbnN1bWluZyBhbG1vc3Qgbm8gcG9seXVuc2F0dXJhdGVkIGZhdHR5IGFjaWRzLiBUaGVzZSBhcmUgZmF0cyB0aGF0IGZvdW5kIGluIHBsYW50LWJhc2VkIHNvdXJjZXMgbGlrZSBzZWVkcyBhbmQgbnV0cy4gQWNjb3JkaW5nIHRvIGFuIFthcnRpY2xlXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM0ODU5NDAxLyl7dGFyZ2V0PSJfYmxhbmsifSBhYm91dCBwb2x5dW5zYXR1cmF0ZWQgZmF0dHkgYWNpZHMgYW5kIGl0cyBpbmZsdWVuY2Ugb24gaGVhbHRoOgoKPiBDb3JvbmFyeSBoZWFydCBkaXNlYXNlIChDSEQpIGlzIHRoZSBsZWFkaW5nIGNhdXNlIG9mIGRlYXRoIHdvcmxkd2lkZSAuLi4gVGhlIHR5cGVzIG9mIGRpZXRhcnkgZmF0cyBjb25zdW1lZCBwbGF5IGFuIGltcG9ydGFudCByb2xlIGluIENIRCByaXNrLCByZXByZXNlbnRpbmcga2V5IG1vZGlmaWFibGUgcmlzayBmYWN0b3JzLi4uSW4gcGFydGljdWxhciwgaGlnaGVyIGludGFrZXMgb2YgdHJhbnMgZmF0IChURkEpIGFuZCBvZiBzYXR1cmF0ZWQgZmF0IChTRkEpIHJlcGxhY2luZyDPieKAkDYgKG7igJA2KSBwb2x5dW5zYXR1cmF0ZWQgZmF0IChQVUZBKSBhcmUgYXNzb2NpYXRlZCB3aXRoIGluY3JlYXNlZCBDSEQuLi4gd2hlcmVhcyBoaWdoZXIgaW50YWtlIG9mIFBVRkEgcmVwbGFjaW5nIGVpdGhlciBTRkEgb3IgY2FyYm9oeWRyYXRlIGlzIGFzc29jaWF0ZWQgd2l0aCBsb3dlciByaXNrLgoKCkxldCdzIGdldCBhbiBpZGVhIGFib3V0IGhvdyBjb3VudHJpZXMgY29tcGFyZSBpbiB0ZXJtcyBvZiBob3cgbWFueSBvZiB0aGUgZGlldGFyeSBmYWN0b3JzIGFyZSBjb25zdW1lZCBhdCB0aGUgb3B0aW1hbCBsZXZlbCAodGhlIGBvcHRfYWNoaWV2ZWRgIHZhcmlhYmxlKS4KCmBgYHtyfQoKZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBjb3VudChvcHRfYWNoaWV2ZWQpCgpgYGAKTG9va3MgbGlrZSBvdmVyYWwsIG9ubHkgYHIgMTUyMC80MzYwKjEwMGAgIG9mIGRpZXRhcnkgZmFjdG9ycyBmb3IgYWxsIHRlc3RlZCBwb3B1bGF0aW9ucyB3ZXJlIGF0IG9wdGltYWwgbGV2ZWxzLgoKTGV0J3MgZ2V0IGFuIGlkZWEgYWJvdXQgaG93IGNvdW50cmllcyBjb21wYXJlLgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KCmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgY291bnQob3B0X2FjaGlldmVkLCBsb2NhdGlvbl9uYW1lKSAlPiUKICBmaWx0ZXIob3B0X2FjaGlldmVkID09ICJZZXMiKSAlPiUKICBhcnJhbmdlKC1uKSAlPiUKICBwcmludChuID0gMWUzKQoKYGBgCiMjIyMKCkxvb2tzIGFzIHRob3VnaCBvbiBhdmVyYWdlIHRoZSBwb3B1bGF0aW9ucyAoYm90aCBtYWxlIGFuZCBmZW1hbGUgc2VwYXJhdGVseSkgaW4gUWF0YXIsIFJ3YW5kYSwgYW5kIFR1cmtleSBjb25zdW1wZWQgdGhlIG9wdGltYWwgbGV2ZWwgb2YgaW50YWtlIGZvciB0aGUgbGFyZ2VzdCBudW1iZXIgb2YgZGlldGFyeSBmYWN0b3JzICgxMyBvdXQgb2YgMzAgKGZvciB0aGUgMTUgZGlldGFyeSBmYWN0b3JzIGZvciBtYWxlcyBhbmQgZmVtYWxlcykpLgoKSW4gY29udHJhc3QsIHRoZSBDemVjaCBSZXB1YmxpYywgR3JlZW5sYW5kLCBIdW5nYXJ5LCBTbG92YWtpYSwgU2xvdmVuaWEsIGFuZCB0aGUgVW5pdGVkIFN0YXRlcyBoYWQgdGhlIHBvb3Jlc3QgY29uc3VtcHRpb24gcmF0ZXMgKDI3IG91dCBvZiAzMCB3ZXJlIG5vdCBhdCBvcHRpbWFsIGxldmVscykuCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQoKZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBjb3VudChvcHRfYWNoaWV2ZWQsIGxvY2F0aW9uX25hbWUpICU+JQogIGZpbHRlcihvcHRfYWNoaWV2ZWQgPT0gIk5vIikgJT4lCiAgYXJyYW5nZSgtbikgJT4lCiAgcHJpbnQobiA9IDFlMykKCmBgYAojIyMjCgpMZXQncyBsb29rIGF0IHRoZSByYXcgVVMgZGF0YToKYGBge3J9CmRpZXRfYW5kX2d1aWRlbGluZXMgJT4lCiAgZmlsdGVyKGxvY2F0aW9uX25hbWUgPT0gIlVuaXRlZCBTdGF0ZXMiKSAlPiUKICBnbGltcHNlKCkKCmBgYAoKTGV0J3Mgc2VlIGhvdyBtYWxlcyBhbmQgZmVtYWxlcyBjb21wYXJlIGZvciBhY2hpZXZpbmcgdGhlIG9wdGltYWwgaW50YWtlOgoKYGBge3J9CmNvdW50KGRpZXRfYW5kX2d1aWRlbGluZXMsIHNleCwgb3B0X2FjaGlldmVkKQpgYGAKTG9va3MgcHJldHR5IHNpbWlsYXIsIGJ1dCBpdCBtYXkgYmUgYSBiaXQgYmV0dGVyIGZvciBmZW1hbGVzLiBXZSB3aWxsIGV2YWx1YXRlIHRoaXMgZnVydGhlci4KCkhlcmUgaXMgYSB3YXkgd2UgY2FuIHZpc3VhbGlzZSB0aGlzIHdpdGggdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlLgpUaGUgW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSBwYWNrYWdlIGNyZWF0ZXMgcGxvdHMgYnkgdXNpbmcgbGF5ZXJzLgpOb3RpY2UgaW4gdGhlIGZvbGxvd2luZyBjb2RlIGhvdyB0aGVyZSBpcyBhIHBsdXMgc2lnbiBiZXR3ZWVuIHRoZSBgZ2dwbG90KClgIGZ1bmN0aW9uIGFuZCB0aGUgYGdlb21faGlzdG9ncmFtKClgIGZ1bmN0aW9uLiAKV2l0aCBgZ2dwbG90MmAgd2Ugc2VsZWN0IHdoYXQgZGF0YSB3ZSB3b3VsZCBsaWtlIHRvIHBsb3QgdXNpbmcgdGhlIGZpcnN0IGZ1bmN0aW9uIChgZ2dwbG90KClgKSBhbmQgdGhlbiB3ZSBhZGQgb24gYWRkaXRpb25hbCBsYXllcnMgb2YgY29tcGxleGl0eSAodGhlc2UgbGF5ZXJzIGNhbiBldmVuIGludm9sdmUgZGlmZmVyZW50IGRhdGEpLiBUaGUgYGFlcygpYCBhcmd1bWVudCBzcGVjaWZpZXMgd2hhdCBhc3BlY3RzIG9mIHRoZSBkYXRhIHdpbGwgYmUgcGxvdHRlZCB3aGVyZS4gdGhlIGBnZW9tXypgIGZ1bmN0aW9uIHNwZWNpZmllcyB3aGF0IHR5cGUgb2YgcGxvdCB0byBjcmVhdGUgKGUuZy4gYGdlb21faGlzdG9ncmFtKClgIGNyZWF0ZSBhIGhpc3RvZ3JhbSkuIAoKV2Ugd2lsbCBzZWUgbGF0ZXIgaG93IHdlIGNhbiBhZGQgbWFueSBsYXllcnMgdG8gcGxvdHMgd2l0aCBgZ2dwbG90MmAuIEZvciBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIG9uIHVzaW5nIGBnZ3Bsb3QyYCwgc2VlIHRoaXMgW2Nhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtaGVhbHRoZXhwZW5kaXR1cmUvb2NzLWhlYWx0aGV4cGVuZGl0dXJlLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uCgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lcyAlPiUKICBnZ3Bsb3QoYWVzKG9wdF9hY2hpZXZlZCAsIGNvbD0gc2V4KSkrCiAgZ2VvbV9iYXIoKQpgYGAKQ29udGludWluZyB3aXRoIGBnZ3Bsb3QyYCB3ZSB3aWxsIG5vdyBjcmVhdGUgYSBkaWZmZXJlbnQgcGxvdCAtIHRoaXMgdGltZSB3ZSB3aWxsIGNyZWF0ZSBhIHNlcmllcyBvZiBib3hwbG90cy4gV2Ugd2lsbCB1c2UgdGhlIGBmYWNldF93cmFwKClgIGZ1bmN0aW9uIG9mIGdncGxvdDIgdG8gYWxsb3cgdXMgdG8gY3JlYXRlIG1hbnkgZGlmZmVyZW50IHBsb3RzIHNpbXVsdGFuZW91c2x5LiBJbiB0aGlzIGNhc2Ugd2UgY2FuIGxvb2sgYXQgYm94cGxvdHMgZm9yIHRoZSBkaWZmZXJlbnQgZGlldGFyeSBmYWN0b3JzIGNvbG9yZWQgYnkgc2V4LiBUaGUgYHNjYWxlc2AgYXJndW1lbnQgd2hlbiBzZXQgdG8gYCJmcmVlImAgbWVhbnMgdGhhdCBlYWNoIG9mIHRoZSBzZXF1ZW50dWFsIHBsb3QgY3JlYXRlZCBieSB0aGUgZmFjZXQgY2FuIGhhdmUgYSBkaWZmZXJudCBzY2FsZSBmb3IgdGhlIHkgYXhpcywgb3RoZXJ3aXNlLCBieSBkZWZhdWx0IHRoZXkgYXJlIGNvbnN0cmFpbmVkIHRvIHRoZSBzYW1lIHNjYWxlLgoKCmBgYHtyfQoKZGlldF9hbmRfZ3VpZGVsaW5lcyU8PiUKICBtdXRhdGUoZm9vZF90b19wbG90ID0KICBzdHJfcmVwbGFjZSggCiAgc3RyaW5nID1wdWxsKGRpZXRfYW5kX2d1aWRlbGluZXMsZm9vZCksIAogIHBhdHRlcm4gPSAiICIsIAogIHJlcGxhY2VtZW50ID0gIlxuIikpCgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGdncGxvdChhZXMoeSA9IG1lYW5fcGVyY2VudCAsIHg9IHNleCwgY29sb3IgPSBzZXgpKSsKICBnZW9tX2JveHBsb3QoKSsKICBmYWNldF93cmFwKH5mb29kX3RvX3Bsb3QsIHNjYWxlcyA9ICJmcmVlIiwgbnJvdyA9IDMsIHN0cmlwLnBvc2l0aW9uID0gInJpZ2h0IikrCiAgdGhlbWUoc3RyaXAudGV4dC55ICA9ICBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNzAsIGhqdXN0ID0gMSkpCmBgYAoKCklmIHdlIGp1c3QgbG9vayBhdCBkaWZmZXJlbmNlcyBieSBzZXggZm9yIHRoZSBzcGVjaWZpYyBkaWV0YXJ5IGZhY3RvcnMsICBtYWxlcyBhcHBlYXIgdG8gcG90ZW50aWFsbHkgY29uc3VtZSBtb3JlIG9mIG1hbnkgb2YgdGhlIGZhY3RvcnMsIGluY2x1ZGluZyBwb3NzaWJseSBtb3JlIHNvZGl1bSwgZmliZXIsIGNhbGNpdW0sIHJlZCBtZWF0LCBhbmQgc3VnYXItc3dlZXRlbmVkIGJldmVyYWdlcyB0aGFuIGZlbWFsZXMuIEZlbWFsZXMgbWF5IGNvbnN1bWUgbW9yZSBmcnVpdC4KCiMjIyAgRXhwbG9yaW5nIHRoZSBkYXRhIHNlcGFyYXRlZCBieSBhZ2UKCk5vdyB3ZSB3aWxsIHRha2UgYSBsb29rIGF0IHRoZSBkYXRhIHRoYXQgaXMgc2VwYXJhdGVkIGJ5IGFnZSBncm91cHMuCgpGaXJzdCwgcmVjYWxsIHRoYXQgd2UgaGF2ZSAxNSBkaWZmZXJlbnQgYWdlIGdyb3VwcyBzdGFydGluZyBmcm9tIGFnZSAyNSB0byA5NSBwbHVzLgpgYGB7cn0KYWxsX2FnZV9kaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogY291bnQoYWdlX2dyb3VwX25hbWUpCmBgYAoKCgpgYGB7ciwgZmlnLmhlaWdodD0xNX0KCnNlcF9hZ2VfZGlldF9kYXRhICU+JQogIGdncGxvdChhZXMoeSA9IG1lYW4gLCB4PSBhZ2VfZ3JvdXBfbmFtZSwgY29sID0gc2V4KSkrCiAgZ2VvbV9ib3hwbG90KCkrCiAgZmFjZXRfd3JhcCh+Zm9vZCwgc2NhbGVzID0gImZyZWUiLCBucm93ID0gNikrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA3MCwgaGp1c3QgPSAxKSkKCiMgc2VwX2FnZV9kaWV0X2RhdGEgJT4lCiMgICBnZ3Bsb3QoYWVzKHkgPSBtZWFuICwgeD0gYWdlX2dyb3VwX25hbWUsIGNvbCA9IHNleCkpKwojICAgZ2VvbV9ib3hwbG90KCkrCiMgICBmYWNldF93cmFwKH5mb29kLCBzY2FsZXMgPSAiZnJlZSIpKwojICAgZmFjZXRfd3JhcCh+Zm9vZCwgc2NhbGVzID0gImZyZWUiLCBucm93ID0gMywgc3RyaXAucG9zaXRpb24gPSAicmlnaHQiKSsKIyAgIHRoZW1lKHN0cmlwLnRleHQueSAgPSAgZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKIyAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNzAsIGhqdXN0ID0gMSkpCmBgYAoKV2UgY2FuIHNlZSBmcm9tIHRoZXNlIHBsb3RzIHRoYXQgdGhlcmUgYXBwZWFycyB0byBiZSBhZ2UgZGlmZmVyZW5jZXMgYW5kIGdlbmRlciBkaWZmZXJlbmNlcyBmb3Igc29tZSBvZiB0aGUgZGlmZmVyZW50IGRpZXRhcnkgZmFjdG9ycy4gV2Ugd2lsbCB3b3JrIHRvIGNyZWF0ZSBjbGVhcmVyIGZpZ3VyZXMgbGF0ZXIgb24uIEhvd2V2ZXIgdGhlc2UgZmlndXJlcyBoYXZlIGdpdmVuIHVzIGEgYmV0dGVyIHNlbnNlIG9mIHRoZSBkYXRhIHRoYXQgd2UgYXJlIHdvcmtpbmcgd2l0aC4KCgojIyBEYXRhIEFuYWx5c2lzCgpSZWNhbGwgd2hhdCBvdXIgbWFpbiBxdWVzdGlvbiB3ZXJlOgoKIyMjIyB7Lm1haW5fcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBPdXIgbWFpbiBxdWVzdGlvbnMgYXJlOiA8L3U+PC9iPgoKMSkgV2hhdCBhcmUgdGhlIGdsb2JhbCB0cmVuZHMgZm9yIHBvdGVudGlhbGx5IGhhcm1mdWwgZGlldHM/CjIpIEhvdyBkbyBtYWxlcyBhbmQgZmVtYWxlcyBjb21wYXJlPwozKSBIb3cgZG8gZGlmZmVyZW50IGFnZSBncm91cHMgY29tcGFyZSBmb3IgdGhlc2UgZGlldGFyeSBmYWN0b3JzPwo0KSBIb3cgZG8gZGlmZmVyZW50IGNvdW50cmllcyBjb21wYXJlPyBJbiBwYXJ0aWN1bGFyLCBob3cgZG9lcyB0aGUgVVMgY29tcGFyZSB0byBvdGhlciBjb250cmllcyBpbiB0ZXJtcyBvZiBkaWV0IHRyZW5kcz8KCiMjIyMKCldlIGhhdmUgc29tZSBnZW5lcmFsIHNlbnNlIGFib3V0IGdsb2JhbCB0cmVuZHMgZm9yIHRoZSByaXNrLWFzc29jaWF0ZWQgZGlldGFyeSBmYWN0b3JzLCBob3dldmVyIHdlIHdhbnQgdG8ga25vdyBtb3JlLgoKV2UgYXJlIGludGVyZXN0ZWQgaW4gaG93IHRoZSAyIGdlbmRlcnMgY29tcGFyZSwgaG93IHRoZSAxOTUgZGlmZmVyZW50IGNvdW50cmllcyBjb21wYXJlIGFuZCBob3cgdGhlIDE1IGRpZmZlcm50IGFnZSBncm91cHMgY29tcGFyZS4gV2UgbWF5IGhhdmUgbGVhcm5lZCB0aGF0IHdlIGNhbiBjb21wYXJlIHR3byBncm91cHMgdXNpbmcgYSAkdCQtdGVzdCwgYnV0IGhvdyBjYW4gd2UgY29tcGFyZSBtb3JlIHRoYW4gMiBncm91cHM/IEZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHRoZSAkdCQtdGVzdCBzZWUgdGhpcyBbY2FzZSBzdHVkeV0oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL29jcy1icC1ydXJhbC1hbmQtdXJiYW4tb2Jlc2l0eS8pe3RhcmdldD0iX2JsYW5rIn0uCgoKSW4gb3JkZXIgdG8gbWFrZSBbaW5mZXJlbmNlXShodHRwczovL3d3dy5icml0YW5uaWNhLmNvbS9zY2llbmNlL2luZmVyZW5jZS1zdGF0aXN0aWNzKSBhYm91dCB0aGVzZSBjb21wYXJpc29ucywgaXQgaXMgaGVscGZ1bCB0byBwZXJmb3JtIHN0YXRpc3RpY2FsIHRlc3RzLiBGaXJzdCB3ZSBhcmUgZ29pbmcgdG8gdGFsayBhYm91dCBhIHN0YXRpc3RpY2FsIG1ldGhvZCBjYWxsZWQgcmVncmVzc2lvbi4KClBlcmhhcHMgeW91IGhhdmUgaGVhcmQgYWJvdXQgdGhlIEFOT1ZBIHRlc3Qgd2hpY2ggY2FuIGJlIHVzZWZ1bCBmb3IgdGVzdGluZyBtb3JlIHRoYW4gdHdvIGdyb3Vwcy4gQU5PVkEgc3RhbmRzIGZvciAiQU5hbHlzaXMgT2YgVkFyaWFuY2UiLiBJdCwganVzdCBsaWtlIHRoZSAkdCQtdGVzdCwgaXMgYSBzcGVjaWFsaXplZCB0eXBlIG9mIFtyZWdyZXNzaW9uXShodHRwczovL2xpbmRlbG9ldi5naXRodWIuaW8vdGVzdHMtYXMtbGluZWFyLyl7dGFyZ2V0PSJfYmxhbmsifS4gTW9yZSBvbiB0aGF0IHRvIGNvbWUuLi4KCiMjIyBSZWdyZXNzaW9uCgpTbyB3aGF0IGlzIHJlZ3Jlc3Npb24/CgpUaGUgdGVybSB3YXMgY29pbmVkIGluIDE4NzcgYnkgW1NpciBGcmFuY2lzIEdhbHRvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRnJhbmNpc19HYWx0b24pe3RhcmdldD0iX2JsYW5rIn0gKENoYXJsZXMgRGFyd2luJ3MgaGFsZi1jb3VzaW4hKSBpbiBoaXMgW2FydGljbGVdKGh0dHA6Ly9nYWx0b24ub3JnL2Vzc2F5cy8xODcwLTE4NzkvZ2FsdG9uLTE4NzctdHlwaWNhbC1sYXdzLWhlcmVkaXR5LnBkZiApe3RhcmdldD0iX2JsYW5rIn0gYWJvdXQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGhlcmlkaXRhcnkgdHJhaXRzIGFuZCBwb3B1bGF0aW9uIGF2ZXJhZ2VzLiBIZSBwYXJ0aWN1bGFybHkgZm9jdXNlZCBvbiBbaGVpZ2h0XShodHRwczovL3plbm9kby5vcmcvcmVjb3JkLzE0NDk1NDgjLlhsZl85aE5LaWhjKXt0YXJnZXQ9Il9ibGFuayJ9IGFuZCBraW5zaGlwIG9yIHJlbGF0ZWRuZXNzLiBUaGUgd29yZCBpbiBnZW5lcmFsIG1lYW5zIHRvIGdvIGJhY2sgdG8gYSBzaW1wbGVyIG1vZGUuIEdhbHRvbiBub3RpY2VkIHRoYXQgaW5kaXZpZHVhbHMgd2l0aCBwYXJlbnRzIHdobyBoYWQgYW4gZXh0cmVtZSB0cmFpdCwgc3VjaCBhcyBoZWlnaHQsIHRlbmRlZCB0byBoYXZlIGEgaGVpZ2h0IG1vcmUgc2ltaWxhciB0byB0aGUgYXZlcmFnZSBvZiB0aGUgcG9wdWxhdGlvbiByYXRoZXIgdGhhbiB0aGUgZXh0cmVtZSBoZWlnaHQgb2YgdGhlaXIgcGFyZW50cy4gRm9yIGV4YW1wbGUgaWYgcGFyZW50cyB3ZXJlIHZlcnkgdGFsbCwgdGhlaXIgY2hpbGRyZW4gd2VyZSBsaWtlbHkgdG8gYmUgYSBiaXQgc2hvcnRlciB0aGFuIHRoZWlyIHBhcmVudHMgYW5kIHRoZXJlZm9yZSBjbG9zZXIgdG8gdGhlIHBvcHVsYXRpb24gYXZlcmFnZS4gVGh1cyB0aGUgY2hpbGRyZW4gcmVncmVzc2VkIHRvd2FyZHMgdGhlIG1lYW4gb3IgaW4gR2FsdG9uJ3Mgd29yZHMgdGhlIG9mZnNwcmluZyBzaG93ZWQ6Cgo+ICJhIHJlZ3Jlc3Npb24gdG93YXJkcyBtZWRpb2NyaXR5IgoKU2VlIFtoZXJlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9SZWdyZXNzaW9uX3Rvd2FyZF90aGVfbWVhbil7dGFyZ2V0PSJfYmxhbmsifSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGlzIGhpc3RvcnkuCgpXaGVuIHdlIHRoaW5rIGFib3V0IHRoaXMgZnJvbSBhIHN0YXRpc3RpY2FsIHN0YW5kcG9pbnQsIHJlZ3Jlc3Npb24gYWxsb3dzIHVzIHRvIGVzdGltYXRlIG9yICoqcmVncmVzcyoqIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMgdG8gYSAic2ltcGxlIiBtb2RlbC4gV2UgZG8gdGhpcyBieSAqKmVzdGltYXRpbmcgdGhlIG1lYW4qKiBvZiBhbiBvdXRjb21lLiBUaGlzIGNhbiBiZSB1c2VmdWwgZm9yICoqcHJlZGljdGluZyBmdXR1cmUgdmFsdWVzKiogb2YgdGhlIG91dGNvbWUgYmFzZWQgb24gdGhlIGFwcHJveGltYXRpb24gb2YgdGhlIHJlYWwgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZhcmFpYmxlcyB3aXRoaW4gdGhlIG1vZGVsLgoKVXNpbmcgdGhlIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgbWV0aG9kIHdlIGNhbiBpZGVudGlmeSBhIGxpbmUgdGhhdCBiZXN0IGZpdHMgdGhlIGRhdGEgYnkgbWluaW1pemluZyB0aGUgc3VtIG9mIHRoZSBzcXVhcmVkIGRpc3RhbmNlcyBiZXR3ZWVuIGVhY2ggcG9pbnQgYW5kIHRoZSBsaW5lLiAKCkZpdHRpbmcgYSBsaW5lIHRvIHRoZSBkYXRhIGxpa2UgdGhpcyBhbGxvd3MgdXMgdG8gY3JlYXRlIGEgZm9ybXVsYSBmb3IgdGhlIGxpbmUgdXNpbmcgYW4gKippbnRlcmNlcHQqKiBhbmQgYSAqKnNsb3BlKiosIHNvIHRoYXQgd2UgY2FuIHRoZW4gZXN0aW1hdGUgKiptZWFuKiogdmFsdWVzIG9mICRZJCAoZGVwZW5kZW50L291dGNvbWUgdmFyaWFibGUpIGdpdmVuIGtub3duIHZhbHVlcyBvZiAkWCQgKGluZGVwZW5kZW50L3ByZWRpY3Rvci9jb3ZhcmlhdGUvZXhwbGFuYXRvcnkgdmFyaWFibGUocykpLiBQZW9wbGUgd2lsbCBhbHNvIHNheSB0aGF0IHdlIGFyZSAicmVncmVzc2luZyAkWSQgb24gJFgkLgogCllvdSBtYXkgaGF2ZSBzZWVuIHRoZSBmb3JtdWxhIGZvciBhIGxpbmUgd3JpdHRlbiBsaWtlIHRoaXM6CgokJFkgPSBtWCArIGIkJCAKCjxjZW50ZXI+IG9yIDwvY2VudGVyPgokJFkgPSBhWCArIGIkJAoKSW4gdGhpcyBjYXNlICRtJCBvciAkYSQgaXMgdGhlIHNsb3BlIG9mIHRoZSBsaW5lIGFuZCAkYiQgaXMgYSBjb25zdGFudCBhbmQgcmVwcmVzZW50cyB0aGUgaW50ZXJjZXB0IG9yIHRoZSBwb2ludCB3aGVyZSB0aGUgeSBheGlzIGlzIGNyb3NzZWQgYnkgdGhlIGxpbmUsIHdoZW4gJHggPSAwJC4KCldlIGNhbiBhbHNvIHdyaXRlIHRoaXMgbW9kZWwgbGlrZSB0aGlzOgoKCiQkWSA9IFxiZXRhX3sxfVggK1xiZXRhX3swfSQkCgpOb3cgJFxiZXRhX3sxfSQgY2FsbGVkIEJldGEgb25lIGlzIG91ciBzbG9wZSBub3RhdGlvbiBhbmQgJEIwJCBCZXRhIG5vdCBpcyBvdXIgaW50ZXJjZXB0IG5vdGF0aW9uLgoKSW1wb3J0YW50bHkgdGhlIHNsb3BlICgkbSQgb3IgJGEkIG9yICRcYmV0YV97MX0kKSBnaXZlcyB1cyBhIG1lYXN1cmUgb2YgdGhlIHN0cmVuZ3RoIG9mIHRoZSBpbmZsdWVuY2Ugb2YgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlKHMpKCRYX3tpfSQpIG9uIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgKCRZJCkuCgpDaGVjayBvdXQgdGhpcyBbaW50ZXJhY3RpdmUgZXhwbGFuYXRpb25dKGh0dHA6Ly9zZXRvc2EuaW8vZXYvb3JkaW5hcnktbGVhc3Qtc3F1YXJlcy1yZWdyZXNzaW9uLyl7dGFyZ2V0PSJfYmxhbmsifSBvZiBob3cgdGhlIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgbWV0aG9kIHdvcmtzLgoKSGVyZSBpcyBhbiBpbWFnZSBvZiB3aGF0IHdlIGFyZSBzYXlpbmcgYWJvdXQgdGhlIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgcmVncmVzc2lvbiB0byBmaXQgYSBsaW5lIHRvIGRhdGE6CiFbXShodHRwczovL3FwaC5mcy5xdW9yYWNkbi5uZXQvbWFpbi1xaW1nLTNiMGQ3NjU1YWM3NmVkZjEyNDFmOTcwMTVlZTc1NWI0KQoKIyMjIyMjIFtbc291cmNlXShodHRwczovL3FwaC5mcy5xdW9yYWNkbi5uZXQvbWFpbi1xaW1nLTNiMGQ3NjU1YWM3NmVkZjEyNDFmOTcwMTVlZTc1NWI0KV0KCgoKSW4gc29tZSBjYXNlcyB3ZSBjYW4gZml0IGEgbGluZSBwZXJmZWN0bHkgYW5kIGFsbCBwb2ludHMgd2lsbCBsaWUgb24gdGhlIGxpbmUgd2l0aCBubyBkaXN0YW5jZSB0byB0aGUgbGluZToKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iMzAwcHR4In0KCmRhdGFfeDwtc2FtcGxlKDE6MTAwLCAyMCwgcmVwbGFjZT1UUlVFKQpkYXRhX3k8LWRhdGFfeCArMTAKdGhlZGF0YTwtYmluZF9jb2xzKHg9ZGF0YV94LHk9IGRhdGFfeSkKCmdncGxvdChkYXRhID10aGVkYXRhLCBhZXMoeCA9eCwgeSA9IHkpKSArZ2VvbV9wb2ludCgpICtnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3I9ImJsYWNrIiwgZm9ybXVsYSA9IHkgfiB4KSArc3RhdF9yZWdsaW5lX2VxdWF0aW9uKCkKYGBgCkluIHRoaXMgY2FzZSwgdGhlIHNsb3BlIG9yICRcYmV0YV97MX0kIGlzIDEgYW5kIHRoZSBpbnRlcmNlcHQgaXMgJFxiZXRhX3swfSQgMTAuIFdlIGNhbiBzZWUgdGhhdCBpZiAkWCQgd2VyZSA1MCwgJFkkIHdvdWxkIGJlIGFwcHJveGltYXRlbHkgNjAuIFRoaXMgaXMgdmVyeSB1bnVzYWwgaW4gc3RhdGlzdGljYWwgYW5hbHlzaXMgaG93ZXZlciwgYXMgb2Z0ZW4gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcmlhYmxlcyBpcyBtb3JlIGNvbXBsaWNhdGVkLgoKSW4gb3RoZXIgY2FzZXMgdGhlcmUgd2lsbCBiZSBncmVhdGVyIGRpc3RhbmNlcyBiZXR3ZWVuIHRoZSBsaW5lIGFuZCB0aGUgcG9pbnRzLiBMaWtlIHRoaXMgcmVncmVzc2lvbjoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSIzMDBwdHgifQpzZXQuc2VlZCgxMykKdGhlZGF0YSAlPD4lIG11dGF0ZSh5MiA9IHJub3JtKDIwLCBzZCA9IDQwKSkKCmdncGxvdChkYXRhID0gdGhlZGF0YSwgYWVzKHggPSB4LCB5ID0geTIpKSArCiAgICAgICAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlPUZBTFNFLCBjb2xvcj0iYmxhY2siLCBmb3JtdWxhID0geSB+IHgpICsKICAgICAgICAgICAgZ2VvbV9wb2ludCgpICtzdGF0X3JlZ2xpbmVfZXF1YXRpb24oKQoKYGBgCgoKVGhpcyBjb25jZXB0IGhhcyBiZWVuIGV4dGVuZGVkIHRvIGFsbG93IGZvciBjb21wYXJpc29ucyBvZiAqKmRpZmZlcmVudCB0eXBlcyBvZiBvdXRjb21lcyAodGhlIHlzKSoqLCB0byBpbnZvbHZlICoqdmFyaW91cyBudW1iZXJzIG9mIGNvdmFyaWF0ZXMgKGluZHBlbmRlbnQgdmFyaWFibGVzIC0gdGhlIHhzKSoqLCBhbmQgdG8gYWxsb3cgZm9yICoqZGlmZmVyZW50IHNoYXBlcyBvZiBsaW5lcyoqLiBGb3IgYSBndWlkZSBvbiBob3cgdG8gcGVyZm9ybSByZWdyZXNzaW9ucyBpbiBSIHNlZSBbaGVyZV0oaHR0cDovL3d3dy5tb250ZWZpb3JlLnVsZy5hYy5iZS9+a3ZhbnN0ZWVuL0dCSU8wMDA5LTEvYWMyMDA5MjAxMC9DbGFzczgvVXNpbmclMjBSJTIwZm9yJTIwbGluZWFyJTIwcmVncmVzc2lvbi5wZGYpe3RhcmdldD0iX2JsYW5rIn0uCgpTbyBsZXQncyBnZXQgYmFjayB0byBvdXIgZGF0YS4uLldoYXQgdHlwZXMgb2Ygb3V0Y29tZXMgZG8gd2UgaGF2ZT8KCjxiPjx1Pk91ciBvdXRjb21lcyAoJFkkKTogPC91PjwvYj4KCldlIGNhbiBldmFsdWF0ZSB0aGUgcmF3IGNvbnN1bXB0aW9uIG9yIHRoZSBwZXJjZW50IG9mIG9wdGltYWwgY29uc3VtcHRpb24gdmFsdWVzIHRoYXQgd2UgY2FsY3VsYXRlZC4gVGhlc2Ugb3V0Y29tZXMgd291bGQgYWxsIGJlIHdoYXQgd2UgY2FsbCAqKmNvbnRpbnVvdXMqKiBiZWF1c2Ugb3VyIHZhbHVlcyBjYW4gdGFrZSBvbiBhbnkgbnVtZXJpYyB2YWx1ZSB3aXRoaW4gdGhlIHJhbmdlIG9mIHBvc3NpYmxlIHZhbHVlcy4gQmluYXJ5IG91dGNvbWVzIGluIGNvbnRyYXN0LCAgaGF2ZSBvbmx5IHR3byBwb3NzaWJsZSBjYXRlZ29yaWNhbCB2YWx1ZXMuIFdlIGNhbiBhbHNvIGV2YWx1YXRlIG91ciAqKmJpbmFyeSoqIG91dGNvbWUgb2YgaWYgdGhlIG9wdGltYWwgbGV2ZWwgb2YgY29uc3VtcHRpb24gd2FzIGFjaGlldmVkIG9yIG5vdC4KCkNvbnRpbnVvdXMgb3V0Y29tZXMgY2FuIGJlIGV2YWx1YXRlZCB3aXRoIGxpbmVhciByZWdyZXNzaW9uLCB3aGlsZSBiaW5hcnkgb3V0Y29tZXMgY2FuIGJlIGV2YWx1YXRlZCB3aXRoIGxvZ2lzdGljIHJlZ3Jlc3Npb24uIFNlZSBbaGVyZV0oaHR0cHM6Ly93d3cuYW5hbHl0aWNzdmlkaHlhLmNvbS9ibG9nLzIwMTUvMDgvY29tcHJlaGVuc2l2ZS1ndWlkZS1yZWdyZXNzaW9uLyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgYSBndWlkZSBvbiBkaWZmZXJlbnQgdHlwZXMgb2YgcmVncmVzc2lvbiBtZXRob2RzLgoKV2UgaGF2ZSBib3RoIGNvbnRpbnVvdXMgb3V0Y29tZXMgb2YgcmF3IGNvbnN1bXB0aW9uIHJhdGVzIG9yIHBlcmNlbnRhZ2VzIG9mIGNvbnN1bXB0aW9uIHJlbGF0YXRpdmUgdG8gdGhlIG9wdGltYWwgZ3VpZGVsaW5lIGFtb3VudHMgYXMgd2VsbCBhcyBiaW5hcnkgb3V0Y29tZXMgb2YgInllcyIgb3IgIm5vIiBhYm91dCBpZiBhIHBvcHVsYXRpb24gYWNoaWV2ZWQgdGhlIG9wdGltYWwgYW1vdW50IG9mIGNvbnN1bXB0aW9uLgoKPGI+PHU+T3VyIGNvdmFyaWF0ZXMgKCRYX3tpfSQpOiA8L3U+PC9iPgoKV2UgaGF2ZSBkYXRhIGFib3V0IGFnZSBncm91cCwgc2V4LCBhbmQgcmVnaW9uIGluZm9ybWF0aW9uZm9yIGFsbCBvZiBvdXIgb3V0Y29tZXMuCgpBZ2FpbiB3ZSBhcmUgaW50ZXJlc2V0ZWQgaW4gY29tcGFyaW5nIHRoZSBzZXhlcywgdGhlIGRpZmZlcmVudCBhZ2UgZ3JvdXBzLCBhbmQgdGhlIGRpZmZlcmVudCBjb3VudHJpZXMgZm9yIHRoZWlyIGNvbnN1bXB0aW9uIG9mIHRoZSBkaWZmZXJlbnQgZGlldGFyeSBmYWN0b3JzLiBXZSBjYW4gYXBwbHkgcmVncmVzc2lvbiB0byBkZXRlcm1pbmUgaWYgdGhlcmUgaXMgYW55IGluZmx1ZW5jZSBvZiB0aGVzZSBncm91cCBpZGVudGl0aWVzIG9uIHRoZSBkaWV0YXJ5IGNvbnN1bXB0aW9uIG91dGNvbWVzLiAKCgpCZWZvcmUgd2UgZ2V0IHN0YXJ0ZWQsIGxldCdzIHJlbW92ZSB0aGUgZ2xvYmFsIHZhbHVlcyBmcm9tIG91ciBkYXRhIGFuZCBzZXQgdGhlbSBhc2lkZSwgYXMgdGhpcyBpcyByZWFsbHkgYSBtZWFuIG9mIGFsbCB0aGUgY291bnRyeSB2YWx1ZXMuCgpgYGB7cn0KZ2xvYmFsIDwtIGRpZXRfYW5kX2d1aWRlbGluZXMgJT4lIGZpbHRlcihsb2NhdGlvbl9uYW1lID09ICJHbG9iYWwiKQpkaWV0X2FuZF9ndWlkZWxpbmVzICU8PiUgZmlsdGVyKGxvY2F0aW9uX25hbWUgIT0gIkdsb2JhbCIpCmBgYAoKIyMjIEluZmx1ZW5jZSBvZiBzZXggb24gZGlldGFyeSBvdXRjb21lcwoKTGV0J3MgZm9jdXMgb24gdGhlIGRpZXRhcnkgZmFjdG9ycyB0aGF0IGFwcGVhcmVkIHRvIHBvdGVudGlhbGx5IGhhdmUgYSBkaWZmZXJlbmNlIGJldHdlZW4gZ2VuZGVycyBiYXNlZCBvbiBvdXIgZmlndXJlIGluIG91ciBleHBsb3JhdG9yeSBhbmFseXNpcy4KCj4gIklmIHdlIGp1c3QgbG9vayBhdCBkaWZmZXJlbmNlcyBieSBzZXggZm9yIHRoZSBzcGVjaWZpYyBkaWV0YXJ5IGZhY3RvcnMsICBtYWxlcyBhcHBlYXIgdG8gcG90ZW50aWFsbHkgY29uc3VtZSBtb3JlIG9mIG1hbnkgb2YgdGhlIGZhY3RvcnMsIGluY2x1ZGluZyBwb3NzaWJseSBtb3JlIHNvZGl1bSwgZmliZXIsIGNhbGNpdW0sIHJlZCBtZWF0LCBhbmQgc3VnYXItc3dlZXRlbmVkIGJldmVyYWdlcyB0aGFuIGZlbWFsZXMuIEZlbWFsZXMgbWF5IGNvbnN1bWUgbW9yZSBmcnVpdC4iCgpGaXJzdCBsZXQncyB0YWtlIGEgbG9vayBhdCByZWQgbWVhdC4KCldlIGNhbiBjb21wYXJlIHRoZSByZWQgbWVhdCBjb25zdW1wdGlvbiBvZiBtYWxlcyBhbmQgZmVtYWxlcyBhcm91bmQgdGhlIHdvcmxkIHVzaW5nIHRoZSB3ZWxsIGtub3duICR0JC10ZXN0IHVzaW5nIHRoZSBgdC50ZXN0KClgIGZ1bmN0aW9uIGFuZCBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHVzaW5nIHRoZSBgbG0oKWAgZnVuY3Rpb24gKGJvdGggYXJlIGluY2x1ZGVkIGluIGBzdGF0c2AgcGFja2FnZSB0aGF0IGlzIGluc3RhbGxlZCB3aXRoIFIpIGFuZCB3ZSB3aWxsIGdldCB0aGUgKipzYW1lIHJlc3VsdHMqKi4gU2VlIFtoZXJlXShodHRwczovL3NjaWVudGlmaWNhbGx5c291bmQub3JnLzIwMTcvMDYvMDgvdC10ZXN0LWFzLWxpbmVhci1tb2RlbHMtci8pe3RhcmdldD0iX2JsYW5rIn0gZm9yIGFkZGl0aW9uYWwgZXhwbGFuYXRpb24gYWJvdXQgd2h5IHRoYXQgaXMgdGhlIGNhc2UuIFtIZXJlXShodHRwczovL3Rvd2FyZHNkYXRhc2NpZW5jZS5jb20vZXZlcnl0aGluZy1pcy1qdXN0LWEtcmVncmVzc2lvbi01YTNiZjIyYzQ1OWMpe3RhcmdldD0iX2JsYW5rIn0gYW5kIFtoZXJlXShodHRwczovL2xpbmRlbG9ldi5naXRodWIuaW8vdGVzdHMtYXMtbGluZWFyLyl7dGFyZ2V0PSJfYmxhbmsifSBhcmUgYWxzbyBncmVhdCBzb3VyY2VzIGFib3V0IGhvdyBtYW55IGNvbW1vbmx5IGtub3duIHN0YXRpc3RpY2FsIHRlc3RzIGFyZSBzcGVjaWFsaXplZCBmb3JtcyBvZiByZWdyZXNzaW9uLgoKQmVmb3JlIHdlIGdldCBzdGFydGVkLCBsZXQncyB0aGluayBhYm91dCB0aGUgYXNzdW1wdGlvbnMgb2YgYm90aCB0ZXN0cy4KCgojIyMjICR0JC10ZXN0IGFzc3VtcHRpb25zOgoKMSkgTm9ybWFsaXR5IG9mIHRoZSBkYXRhIGZvciBib3RoIGdyb3VwcyAodGhpcyBpcyBub3QgYXMgbXVjaCBvZiBhbiBpc3N1ZSBpZiB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpcyByZWxhdGl2ZWx5IGxhcmdlIHRvdGFsIG4+MzAgLSB3aGljaCBpcyBpbmRlZWQgdGhlIGNhc2UgZm9yIHVzISkKMikgRXF1YWwgdmFyaWFuY2UgYmV0d2VlbiB0aGUgdHdvIGdyb3VwcyAobWFrZSBzdXJlIHlvdSBkbyB0aGUgY29ycmVjdCB0ZXN0IGlmIHRoZSBkYXRhIGlzIG5vdCBub3JtYWwpCjMpIEJhbGFuY2VkIHNhbXBsZSBzaXplcyBvZiB0aGUgdHdvIGdyb3VwcyAoZ290IHRoYXQhKQo0KSBJbmRlcGVuZGVudCBvYnNlcnZhdGlvbnMgKG9yIGluZGVwZW5kZW50IHBhaXJlZCBvYnNlcnZhdGlvbnMgLSBnb3QgdGhhdCB0b28hKQoKV2UgY2FuIGV2YWx1YXRlIGlmIG91ciBkYXRhIGlzIFtub3JtYWxseSBkaXN0cmlidXRlZF0oaHR0cHM6Ly93d3cucGh5c2lvbG9neS5vcmcvZG9pL2Z1bGwvMTAuMTE1Mi9hZHZhbi4wMDA2NC4yMDE3KSBieSBwbG90dGluZyB0aGUgZGlzdHJpYnV0aW9uIGFuZCBieSBjcmVhdGluZyBRLVEgcGxvdHMuIAoKPHU+SWYgb3VyIGRhdGEgaXMgbm90IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCB3ZSBjYW4gY29uc2lkZXIgdGhlc2Ugb3B0aW9uczo8L3U+CgoxKSBXZSBjYW4gc3RpbGwgcGVyZm9ybSBhIHQtdGVzdCBpZiBvdXIgbiBpcyBsYXJnZQoyKSBXZSBjYW4gdHJhbnNmb3JtIHRoZSBkYXRhIGJlZm9yZSBwZXJmb3JtaW5nIGEgdC10ZXN0CjMpIFdlIGNhbiB1c2UgYSBub25wYXJhbWV0cmljIHRlc3QgKFdpbGNveG9uIHNpZ25lZCByYW5rIHRlc3QsIHRoZSBXaWxjb3hvbiByYW5rIHN1bSB0ZXN0LCBhbmQgdGhlIFR3by1zYW1wbGUgS29sbW9nb3Jvdi1TbWlybm92IChLUykgdGVzdCkKNCkgV2UgY2FuIHBlcmZvcm0gYSB0LXRlc3Qgd2l0aCByZXNhbXBsaW5nIG1ldGhvZHMgKHdoaWNoIHNob3VsZCBiZSBlc3BlY2lhbGx5IGNvbnNpZGVyZWQgd2hlbiB0aGUgZ3JvdXBzIGFyZSBpbWJhbGFuY2VkKQoKU2VlIHRoaXMgW2Nhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtcnVyYWwtYW5kLXVyYmFuLW9iZXNpdHkpe3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gJHQkLXRlc3QgYXNzdW1wdGlvbnMuCgojIyMjIExpbmVhciByZWdyZXNzaW9uIGFzc3VtcHRpb25zCkwgKGxpbmVhcikgLSBUaGVyZSBpcyBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdmFyaWFibGVzLgpJIChpbmRlcGVuZGVudCkgLSBUaGUgc2FtcGxlcyBhcmUgaW5kZXBlbmRlbnQgZnJvbSBvbmUgYW5vdGhlci4KTiAobm9ybWFsKSAtIFRoZSByZXNpZHVhbHMgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgpFIChlcXVhbCB2YXJpYW5jZXMpIC0gVGhlIHZhcmlhbmNlIG9mIHRoZSBncm91cHMgaXMgc2ltaWxhci4KCiMjIyMgRGlzdHJpYnV0aW9ucwoKSW4gb3JkZXIgdG8gYXBwbHkgYSBzdGF0aXN0aWNhbCB0ZXN0IHRvIGNvbXBhcmUgdGhlIG1lYW5zLCBvbmUgb2YgdGhlIGZpcnN0IHRoaW5ncyB0byBkbyBpcyB0byBleHBsb3JlIHRoZSBmcmVxdWVuY3kgb2YgdGhlIGRpZmZlcmVudCBvYnNlcnZlZCB2YWx1ZXMuIApPbmUgd2F5IHRvIHN1bW1hcml6ZSB0aGUgZnJlcXVlbmN5IG9mIGRpZmZlcmVudCBvYnNlcnZlZCB2YWx1ZXMgaXMgdGhlIDxiPmZyZXF1ZW5jeSBkaXN0cmlidXRpb248L2I+LCB3aGljaCBjYW4gYmUgc2hvd24gaW4gYSB0YWJsZSBvciBhIHBsb3QuIApTZWUgW2hlcmVdKGh0dHA6Ly9vbmxpbmVzdGF0Ym9vay5jb20vMi9pbnRyb2R1Y3Rpb24vZGlzdHJpYnV0aW9ucy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGRpc3RyaWJ1dGlvbnMuIAoKV2Ugd2lsbCB1c2UgdGhlIGBnZW9tX2hpc3RvZ3JhbSgpYCBvZiB0aGUgYGdncGxvdDJgcGFja2FnZSB0byBjcmVhdGUgYSBoaXN0b2dyYW0gdG8gZXZhbHVhdGUgdGhlIGZyZXF1ZW5jeSBkaXN0cmlidXRpb25zIG9mIG91ciBkYXRhLiBUaGUgYGZhY2V0X3dyYXAoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIGFsbG93cyB1cyB0byBsb29rIGF0IGRpZmZlcmVudCBwYXJ0cyBvZiBvdXIgZGF0YSBpbiBzZXBhcmF0ZSBwbG90cy4KCmBgYHtyfQpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09InJlZCBtZWF0IikgJT4lCiAgZ2dwbG90KGFlcyh4PW1lYW5fcGVyY2VudCkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF93cmFwKH4gc2V4KSAKYGBgCgpOb3cgd2UgYWRkIGFub3RoZXIgZGltZW5zaW9uIHRvIG91ciBmYWNldCB3aXRoIHRoZSBwbHVzIHNpZ24uIE5vdyBpdCBiZWNvbWVzIHZlcnkgdXNlZnVsIHRoYXQgd2UgcmVmb3JtbWF0ZWQgb3VyIGRhdGEgdG8gdGhlIGxvbmcgZm9ybWF0LCBhcyBpdCBtYWtlcyBpdCBlYXN5IHRvIGZhY2V0IGFjcm9zcyB0aGUgZGlmZmVyZW50IHBlcmNlbnRhZ2VzIHRoYXQgd2UgY2FsY3VsYXRlZC4gV2UgY2FuIHNwZWNpZnkgdGhhdCB3ZSB3YW50IHRvIGhhdmUgZGlmZmVyZW50IHkgYXhpcyBzY2FsZXMgdXNpbmcgdGhlIGBzY2FsZXNgIGFyZ3VtZW50IGFzOiAgYHNjYWxlcyA9ICJmcmVlImAuCgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lc19sb25nICU+JQogIGZpbHRlcihmb29kID09InJlZCBtZWF0IikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcGVyY2VudCkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF93cmFwKH4gcGVyY2VudF90eXBlICsgc2V4LCBzY2FsZXMgPSAiZnJlZSIpCgpkaWV0X2FuZF9ndWlkZWxpbmVzX2xvbmcgJT4lCiAgZmlsdGVyKGZvb2QgPT0icmVkIG1lYXQiKSAlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZSA9IHBlcmNlbnQpKSArCiAgZmFjZXRfd3JhcCh+IHBlcmNlbnRfdHlwZSArIHNleCkrCiAgZ2VvbV9xcSgpICsKICBnZW9tX3FxX2xpbmUoKQpgYGAKCkxvb2tzIGxpa2Ugb3VyIGRhdGEgaXMgKipyaWdodCBza2V3ZWQqKi4KCldlIGNhbiB0cmFuc2Zvcm0gb3VyIGRhdGEgdG8gbWFrZSBpdCBtb3JlIG5vcm1hbGx5IGRpc3RydWJ1dGVkLiBXaGVuIGRhdGEgaXMgaGlnaGx5IHJpZ2h0IHNrZXdlZCwgYSBsb2cgdHJhbnNmb3JtYXRpb24gaXMgb2Z0ZW4gaGVscGZ1bC4KCkxldCdzIHRha2UgYSBsb29rIGEgdGhlIGxvZyBvZiBvdXIgcGVyY2VudCBvZiBvcHRpbWFsIGNvbnN1bXB0aW9uIHZhbHVlcy4KCmBgYHtyfQpkaWV0X2FuZF9ndWlkZWxpbmVzX2xvbmcgJT4lCiAgICBmaWx0ZXIoZm9vZCA9PSJyZWQgbWVhdCIpICU+JQogIGdncGxvdChhZXMoeCA9IGxvZzEwKHBlcmNlbnQpKSkgKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGZhY2V0X3dyYXAofiBwZXJjZW50X3R5cGUpCgpkaWV0X2FuZF9ndWlkZWxpbmVzX2xvbmcgJT4lCiAgICBmaWx0ZXIoZm9vZCA9PSJyZWQgbWVhdCIpICU+JQogIGdncGxvdChhZXMoc2FtcGxlID0gbG9nMTAocGVyY2VudCkpKSArCiAgZmFjZXRfd3JhcCh+IHBlcmNlbnRfdHlwZSkrCiAgZ2VvbV9xcSgpICsKICBnZW9tX3FxX2xpbmUoKQpgYGAKCgpIb3cgYWJvdXQgdGhlIHJhdyBjb25zdW1wdGlvbiBkYXRhOgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lc19sb25nICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIGdncGxvdChhZXMoeCA9IChtZWFuKSkpICsKICBnZW9tX2hpc3RvZ3JhbSgpCmBgYApBbHNvIHJpZ2h0IHNrZXdlZC4uLiBzbyBsZXQncyB0cnkgdGFraW5nIHRoZSBsb2cgb2YgdGhlIG1lYW4gdmFsdWU6CgpgYGB7cn0KZGlldF9hbmRfZ3VpZGVsaW5lc19sb25nICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIGdncGxvdChhZXMoeCA9IChsb2cxMChtZWFuKSkpKSArCiAgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKVGhpcyBpcyBiZXR0ZXIgdG9vLgoKT2ssIHNvIHdlIGNhbiBnZXQgb3VyIGRhdGEgdG8gbG9vayBmYWlybHkgbm9ybWFsLCB3aGljaCBpcyBnb29kIGZvciBvdXIgJHQkLXRlc3QgYXNzdW1wdGlvbnMuICBUaGUgb3RoZXIgdGhpbmcgd2UgbmVlZCB0byBjaGVjayBpcyBpZiB0aGUgdmFyaWFuY2UgaW4gcmVkIG1lYXQgY29uc3VtcHRpb24gaXMgc2ltaWxhciBiZXR3ZWVuIHRoZSB0d28gZ2VuZGVycy4gV2UgY2FuIHVzZSB0aGUgYHZhci50ZXN0KClgICBvZiB0aGUgYHN0YXRzYCBwYWNrYWdlIHVzaW5nIHRoZSBsb2cgbm9ybWFsaXplZCBkYXRhLCBhcyB0aGlzIGRhdGEgaXMgZmFpcmx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBXZSBjYW4gdXNlIHRoZSBtb29kLnRlc3Qgb24gdGhlIHJhdyBkYXRhIHdoaWNoIGlzIHNrZXdlZC4KCmBgYHtyfQptb29kLnRlc3QocHVsbChmaWx0ZXIoZGlldF9hbmRfZ3VpZGVsaW5lcywKICAgICAgICAgICAgICAgICAgICAgZm9vZCA9PSAicmVkIG1lYXQiKSwgbWVhbl9wZXJjZW50KSwKICAgICAgICAgcHVsbChmaWx0ZXIoZGlldF9hbmRfZ3VpZGVsaW5lcywKICAgICAgICAgICAgICAgICAgICAgZm9vZCA9PSAicmVkIG1lYXQiKSwgc2V4KSkKCnZhci50ZXN0KGxvZzEwKHB1bGwoZmlsdGVyKGRpZXRfYW5kX2d1aWRlbGluZXMsCiAgICAgICAgICAgICAgICAgICAgIGZvb2QgPT0gInJlZCBtZWF0IiksIG1lYW5fcGVyY2VudCkpfgogICAgICAgICBwdWxsKGZpbHRlcihkaWV0X2FuZF9ndWlkZWxpbmVzLAogICAgICAgICAgICAgICAgICAgICBmb29kID09ICJyZWQgbWVhdCIpLCBzZXgpKQpgYGAKClRoZSBwIHZhbHVlID4uMDUgZm9yIGJvdGggdGVzdHMsIHRodXMgd2UgY2FuIGNvbmNsdWRlIHRoYXQgdGhlcmUgaXMgbm90IGVub3VnaCBldmlkZW5jZSB0byByZWplY3QgdGhlIG51bGwgKG5vIGRpZmZlcmVuY2UgaW4gdGhlIHNwcmVhZCBvZiB0aGUgZGlzdHJpYnV0aW9ucyksIHRodXMgd2UgY29uY2x1ZGUgdGhhdCB2YXJpYW5jZSBpcyByb3VnaGx5IGVxdWFsLiBHcmVhdC4uLiBzbyB3ZSBhcmUgaW4gcHJldHR5IGdvb2Qgc2hhcGUgZm9yIGJvdGggdGhlICR0JC10ZXN0IGFuZCB0aGUgbGluZWFyIHJlZ3Jlc3Npb24uCgpTbyBub3cgd2UgY2FuIGNvbXBhcmluZyB0aGUgY29uc3VtcHRpb24gb2YgcmVkIG1lYXQgYnkgYm90aCBnZW5kZXJzIHVzaW5nIGJvdGggYSAkdCQtdGVzdCBhbmQgYSBsaW5lYXIgcmVncmVzc2lvbjoKCmBgYHtyfQpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIGxtKGxvZzEwKG1lYW5fcGVyY2VudCkgfiBzZXgsIGRhdGE9LikgJT4lCiAgcGxvdCgpCgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIGxtKGxvZzEwKG1lYW5fcGVyY2VudCkgfiBzZXgsIGRhdGE9LikgJT4lCiAgc3VtbWFyeSgpCgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIHQudGVzdChsb2cxMChtZWFuX3BlcmNlbnQpIH4gc2V4LCBkYXRhPSAuLCB2YXIuZXF1YWwgPSBUUlVFKQpgYGAKCk5vdGljZSBob3cgdGhlICR0JCB2YWx1ZSBhbmQgdGhlIHAtdmFsdWUgYXJlIHRoZSBzYW1lISAoV2VsbCBhbG9tb3N0LCB0aGUgJHQkIHZhbHVlIGlzIG5lZ2F0aXZlIGluIHRoZSBgdC50ZXN0KClgIG91dHB1dCBiZWNhdXNlIHRoZSBmZW1hbGUgZ3JvdXAgaXMgYmVpbmcgdXNlZCBhcyByZWZlcmVuY2UgZ3JvdXAsIHdoaWxlIHRoZSBtYWxlIGdyb3VwIGlzIGJlaW5nIHVzZWQgYXMgdGhlIHJlZmVyZW5jZSBncm91cCBpbiBgbG0oKWApLiBXZSBjYW4gZml4IHRoaXMgdXNpbmcgdGhlIGBmY3RfaW5vcmRlcigpYCBmdW5jdGlvbiBvZiB0aGUgYGZvcmNhdHNgIHBhY2thZ2Ugd2hpY2ggaXMgYWxsIGFib3V0IGZhY3RvcnMuIFRoaXMgZnVuY3Rpb24gYWxsb3dzIHVzIHRvIG9yZGVyIHRoZSBmYWN0b3IgYnkgd2hhdCBhcHBlYXJzIGZpcnN0LiBJbiB0aGlzIGNhc2UgIm1hbGUiIGFwcGVhcnMgZmlyc3QsIHNvIG5vdyBvdXIgb3V0cHV0IHdpbGwgbWF0Y2ggdGhhdCBvZiB0aGUgYGxtKClgIGZ1bmN0aW9uLgoKCmBgYHtyfQpkaWV0X2FuZF9ndWlkZWxpbmVzICU8PiUKICBtdXRhdGVfYXQodmFycyhzZXgpLCBmYWN0b3IpCgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIGxtKGxvZzEwKG1lYW5fcGVyY2VudCkgfiBzZXgsIGRhdGE9LikgJT4lCiAgc3VtbWFyeSgpCgpkaWV0X2FuZF9ndWlkZWxpbmVzICU+JQogIG11dGF0ZV9hdCh2YXJzKHNleCksIGZvcmNhdHM6OmZjdF9pbm9yZGVyKSU+JQogIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JQogIHQudGVzdChsb2cxMChtZWFuX3BlcmNlbnQpIH4gc2V4LCBkYXRhPSAuLCB2YXIuZXF1YWwgPSBUUlVFKQoKYGBgCgpOb3cgdGhleSBtYXRjaC4gTm90aWNlIHRoYXQgdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSBhbHNvIG1hdGNoLCBib3RoIHJlc3VsdHMgc2hvdyAzODggZGVncmVlcyBvZiBmcmVlZG9tLiBXZSBhcmUgZXN0aW1hdGluZyAyIHBhcmFtZXRlcnMgZm9yIHRoZSBsaW5lYXIgbW9kZWwgdGhlIHR3byAkXGJldGEkIGNvZWZmaWNpZW50cywgKHRoZSBzbG9wZSBhbmQgaW50ZXJjZXB0KSwgYW5kIGZvciB0aGUgJHQkLXRlc3Qgd2UgYXJlIGVzdGltYXRpbmcgdGhlIG1lYW5zIG9mIHR3byBncm91cHMgKG1hbGVzIGFuZCBmZW1hbGVzKS4gT3ZlcmFsbCB3ZSBoYXZlIHR3byBzYW1wbGVzIChtYWxlIGFuZCBmZW1hbGUpIGZvciBlYWNoIG9mIHRoZSAxOTUgY291bnRyaWVzLiAKClRodXMsIHRoZSBvdmVyYWwgc2FtcGxlIG51bWJlciBpczogJG4gPSAxOTUqMiA9IDM5MCQKCiQkZGYgPSBuIC0gIyBwYXJhbWV0ZXJzIGVzdGltYXRpbmckJCAKVGh1cyB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIGNhbiBiZSBjYWxjdWxhdGVkIGFzOiAkZGYgPSAzOTAgLTIgPSAzODgkCgoKSW4gdGhlIGBsbSgpYCBvdXRwdXQsIHRoZSBCZXRhIG5vdCAoJFxiZXRhX3swfSQpIHdoaWNoIGNhbiBiZSBpbnRlcnByZXRlZCBhcyB0aGUgaW50ZXJjZXB0IG9yIHRoZSBtZWFuIHZhbHVlIHdoZW4gc2V4IGlzIG5vdCBtYWxlIChzbyBpbiB0aGlzIGNhc2Ugd2hlbiBzZXggaXMgZmVtYWxlKSBoYXMgdGhlIHNhbWUgdmFsdWUgYXMgdGhlIGNhbGN1bGF0ZWQgbWVhbiBvZiBpbiB0aGUgYHQudGVzdCgpYCBvdXRwdXQuIFRoZSBCZXRhIG9uZSAoJFxiZXRhX3sxfSQpICBjYW4gYmUgaW50ZXJwcmV0ZWQgYXMgdGhlIHNsb3BlIG9mIHRoZSByZWdyZXNzaW9uIGxpbmUgb3IgdGhlIGRpZmZlcmVuY2UgYmV3dGVlbiB0aGUgbWVhbnMgb2YgdGhlIHR3byBncm91cHMuIFdlIGNhbiBhbHNvIHRoaW5rIG9mIHRoaXMgYXMgYXMgdGhlIGNoYW5nZSBpbiAkWSQgd2l0aCBvbmUgdW5pdCBjaGFuZ2UgaW4gJFgkLiAgCgpJZiB3ZSBzdWJ0cmFjdCB0aGUgbWVhbnMgY2FsY3VsYXRlZCBpbiB0aGUgYHQudGVzdCgpYCBvdXRwdXQsIHdlIGdldCB0aGUgdmFsdWUgb2YgJFxiZXRhX3sxfSQgKHRoZSBzbG9wZSBvciB0aGUgYHNleE1hbGUgZXN0aW1hdGVgKSBvZiB0aGUgYGxtKClgIG91dHB1dCEKCk1lYW4gb2YgbWFsZXMgLSBNZWFuIG9mIGZlbWFsZXMKJDEuOTgzMjU5IC0gMS43OTg4NzIgPTAuMTg0Mzg3JAoKQ29vbCEKCgpMZXQncyBwbG90IHRoZSBkYXRhIHRvIHNlZSB3aGF0IGlzIGhhcHBlbmluZzoKCmBgYHtyfQpkaWV0X2FuZF9ndWlkZWxpbmVzJT4lCiAgZmlsdGVyKGZvb2QgPT0gInJlZCBtZWF0IikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc2V4LCB5ID0gbG9nMTAobWVhbl9wZXJjZW50KSkpICsgCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkrCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAuMikrCiAgc3RhdF9zdW1tYXJ5KGZ1bi55PW1lYW4sIGNvbG91cj0iYmx1ZSIsIGdlb209InBvaW50IiwgCiAgICAgICAgICAgICAgc2hhcGU9MTgsIHNpemU9MykrCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0xLjc5ODg3ICwgc2xvcGUgPSAwLjE4NDM5LCBjb2xvciA9ICJyZWQiKSAKIyB1c2luZyB0aGUgc2xvcGUgYW5kIGludGVyY2VwdCBmcm9tIHRoZSBsbSBvdXRwdXQKCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSBzbG9wZSBvZiB0aGUgbGluZWFyIG1vZGVsIGlzIGVxdWl2YWxlbnQgdG8gdGhlIGRpZmZlcmVuY2UgYmV3dGVlbiB0aGUgbWVhbiBvZiB0aGUgdHdvIGdyb3VwcywgYXMgdGhlIGxpbmVhciBtb2RlbCBsaW5lIGlzIHBhcmFsbGVsIHRvIHRoZSBsaW5lIHRoYXQgY291bGQgYmUgZHJhd24gYmV0d2VlbiB0aGUgdHdvIG1lYW5zLgoKQWxzbywgc2luY2Ugd2UgaGF2ZSBmZW1hbGUgYW5kIG1hbGUgdmFsdWVzIGVhY2ggZnJvbSB0aGUgc2FtZSBjb3VudHJpZXMsIG91ciBkYXRhIGlzIHdoYXQgd2UgY2FsbGVkIHBhaXJlZC4gSXQgd291bGQgYmUgYmV0dGVyIGlmIHdlIG1vZGVsZWQgb3VyIGRhdGEgdGhhdCB3YXkuIEZpcnN0IHdlIHdpbGwgdXNlIHRoZSBgcGl2b3Rfd2lkZXIoKWAgZnVuY3Rpb24gb2YgIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gZ2V0IG91ciBkYXRhIGluIGEgZm9ybWF0IHRoYXQgaXMgZWFzaWVyIHRvIHVzZSBmb3IgdGhpcyBwdXJwb3NlLiBUbyB1c2UgdGhpcyBmdW5jdGlvbiB3ZSBzcGVjaWZ5IHRoZSB2YWx1ZXMgdGhhdCB3ZSB3YW50IHRvIHNlcGFyYXRlIGludG8gbW9yZSB2YXJpYWJsZXMgdXNpbmcgdGhlIGB2YWx1ZXNfZnJvbWAgYXJndW1lbnQgYW5kIHdlIHVzZSB0aGUgYG5hbWVzX2Zyb21gIGFyZ3VtZW50IHRvIHNwZWNpZnkgaG93IHdlIHdhbnQgdG8gc2VwYXJhdGUgdGhlc2Ugb3RoZXIgdmFyaWFibGVzLiBJbiB0aGlzIGNhc2Ugd2Ugd2lsbCBtYWtlIGEgbWFsZSBhbmQgZmVtYWxlIHZlcnNpb24gb2YgYWxsIHRoZSBvdGhlciB2YXJpYWJsZXMgc3BlY2lmaWVkLgoKYGBge3J9Cgp3aWRlX2RpZXQgPC1waXZvdF93aWRlcihkaWV0X2FuZF9ndWlkZWxpbmVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX2Zyb209IGMoY29udGFpbnMoInBlcmNlbnQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRfYWNoaWV2ZWQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfZnJvbT0gc2V4KQoKZ2xpbXBzZSh3aWRlX2RpZXQpCgojIHdpZGVfZGlldCAlPiUKIyAgIGZpbHRlcihmb29kID09ICJyZWQgbWVhdCIpICU+JSAgCiMgICBsbShsb2cxMChtZWFuX3BlcmNlbnRfRmVtYWxlKSAtIGxvZzEwKG1lYW5fcGVyY2VudF9NYWxlKSB+MSwgZGF0YT0gLikgJT4lCiMgICBzdW1tYXJ5KCkKCmxpYnJhcnkobG1lclRlc3QpCgpzdW1tYXJ5KGxtZXIobG9nMTAocHVsbChmaWx0ZXIoZGlldF9hbmRfZ3VpZGVsaW5lcywgZm9vZCA9PSAicmVkIG1lYXQiKSwKICAgICAgICAgICAgICAgICAgbWVhbl9wZXJjZW50KSkgfiAKICAgICAgICAgICAgIHB1bGwoZmlsdGVyKGRpZXRfYW5kX2d1aWRlbGluZXMsIGZvb2QgPT0gInJlZCBtZWF0IiksCiAgICAgICAgICAgICAgICAgIHNleCkrICgxIHwgcHVsbChmaWx0ZXIoZGlldF9hbmRfZ3VpZGVsaW5lcywgZm9vZCA9PSAicmVkIG1lYXQiKSwgbG9jYXRpb25fbmFtZSkpKSkKCnQudGVzdChsb2cxMChwdWxsKGZpbHRlcih3aWRlX2RpZXQsIGZvb2QgPT0gInJlZCBtZWF0IiksCiAgICAgICAgICAgICAgICAgIG1lYW5fcGVyY2VudF9GZW1hbGUpKSwgCiAgICAgICBsb2cxMChwdWxsKGZpbHRlcih3aWRlX2RpZXQsIGZvb2QgPT0gInJlZCBtZWF0IiksCiAgICAgICAgICAgICAgICAgIG1lYW5fcGVyY2VudF9NYWxlKSksCiAgICAgICB2YXIuZXF1YWwgPSBUUlVFLCBwYWlyZWQgPSBUUlVFKQpgYGAKCllvdSBjYW4gc2VlIHRoYXQgbm93IG91ciBkZWdyZWVzIG9mIGZyZWVkb20gYXJlIDE5NCwgd2hpY2ggbWFrZXMgc2Vuc2UgYmVjdWFzZSBub3cgd2UgaGF2ZSBtYXRjaGVkIG9yIHBhaXJlZCB2YWx1ZXMgZm9yIHRoZSAxOTUgZGlmZmVyZW50IHJlZ2lvbnMgYW5kIHNvICRkZiA9IG4tMSA9IDE5NSAtMSA9IDE5NCQuCgpBZ2FpbiB3ZSBnZXQgdGhlIHNhbWUgJHQkLXZhbHVlIGFuZCBwLXZhbHVlIHdpdGggYm90aCB0ZXN0cy4KCldlIGNhbiBjb25jbHVkZSBmcm9tIHRoZXNlIHRlc3RzIHRoYXQgd2UgaGF2ZSBlbm91Z2ggZXZpZGVuY2UgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGVyZSBpcyBubyBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG1lYW5zIG9yIHRoYXQgc2V4IGhhcyBubyBhc3NvY2lhdGlvbiBvciBpbmZsdWVuY2Ugb24gcmVkIG1lYXQgY29uc3VtcHRpb24uIFRoZXJlZm9yZSwgaXQgYXBwZWFycyB0aGF0IG1lbiBjb25zdW1lIHNpZ25pZmljYW50bHkgbW9yZSByZWQgbWVhdCB0aGFuIGZlbWFsZXMgZ2xvYmFsbHkuIAoKTGV0J3MgY2hvb3NlIGFub3RoZXIgZGlldGFyeSBmYWN0b3IgdG8gY29tcGFyZSBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzLiAKCmBgYHtyfQoKZGlldF9hbmRfZ3VpZGVsaW5lc19sb25nICU+JQogIGZpbHRlcihmb29kID09ImZydWl0cyIpICU+JQogIGdncGxvdChhZXMoeD1sb2cxMChwZXJjZW50KSkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF93cmFwKH4gcGVyY2VudF90eXBlKQoKCmRpZXRfYW5kX2d1aWRlbGluZXNfbG9uZyAlPiUKICAgIGZpbHRlcihmb29kID09ImZydWl0cyIpICU+JQogIGdncGxvdChhZXMoc2FtcGxlID0gbG9nMTAocGVyY2VudCkpKSArCiAgZmFjZXRfd3JhcCh+IHBlcmNlbnRfdHlwZSkrCiAgZ2VvbV9xcSgpICsKICBnZW9tX3FxX2xpbmUoKQoKbW9vZC50ZXN0KHB1bGwoZmlsdGVyKGRpZXRfYW5kX2d1aWRlbGluZXMsCiAgICAgICAgICAgICAgICAgICAgIGZvb2QgPT0gImZydWl0cyIpLCBtZWFuX3BlcmNlbnQpLAogICAgICAgICBwdWxsKGZpbHRlcihkaWV0X2FuZF9ndWlkZWxpbmVzLAogICAgICAgICAgICAgICAgICAgICBmb29kID09ICJmcnVpdHMiKSwgc2V4KSkKCnZhci50ZXN0KGxvZzEwKHB1bGwoZmlsdGVyKGRpZXRfYW5kX2d1aWRlbGluZXMsCiAgICAgICAgICAgICAgICAgICAgIGZvb2QgPT0gImZydWl0cyIpLCBtZWFuX3BlcmNlbnQpKX4KICAgICAgICAgcHVsbChmaWx0ZXIoZGlldF9hbmRfZ3VpZGVsaW5lcywKICAgICAgICAgICAgICAgICAgICAgZm9vZCA9PSAiZnJ1aXRzIiksIHNleCkpCiMgd2lkZV9kaWV0ICU+JQojICAgZmlsdGVyKGZvb2QgPT0gImZydWl0cyIpICU+JSAgCiMgICBsbShsb2cxMChtZWFuX3BlcmNlbnRfRmVtYWxlKSAtIGxvZzEwKG1lYW5fcGVyY2VudF9NYWxlKSB+MSwgZGF0YT0gLikgJT4lCiMgICBzdW1tYXJ5KCkKCnN1bW1hcnkobG1lcihsb2cxMChwdWxsKGZpbHRlcihkaWV0X2FuZF9ndWlkZWxpbmVzLCBmb29kID09ICJmcnVpdHMiKSwKICAgICAgICAgICAgICAgICAgbWVhbl9wZXJjZW50KSkgfiAKICAgICAgICAgICAgIHB1bGwoZmlsdGVyKGRpZXRfYW5kX2d1aWRlbGluZXMsIGZvb2QgPT0gImZydWl0cyIpLAogICAgICAgICAgICAgICAgICBzZXgpKyAoMSB8IHB1bGwoZmlsdGVyKGRpZXRfYW5kX2d1aWRlbGluZXMsIGZvb2QgPT0gImZydWl0cyIpLCBsb2NhdGlvbl9uYW1lKSkpKQoKdC50ZXN0KGxvZzEwKHB1bGwoZmlsdGVyKHdpZGVfZGlldCwgZm9vZCA9PSAiZnJ1aXRzIiksCiAgICAgICAgICAgICAgICAgIG1lYW5fcGVyY2VudF9GZW1hbGUpKSwgCiAgICAgICBsb2cxMChwdWxsKGZpbHRlcih3aWRlX2RpZXQsIGZvb2QgPT0gImZydWl0cyIpLAogICAgICAgICAgICAgICAgICBtZWFuX3BlcmNlbnRfTWFsZSkpLAogICAgICAgdmFyLmVxdWFsID0gVFJVRSwgcGFpcmVkID0gVFJVRSkKCm1lYW5zPC13aWRlX2RpZXQgJT4lIAogICBmaWx0ZXIoZm9vZD09ICJmcnVpdHMiKSAlPiUgCiAgIHN1bW1hcmlzZShmZW1hbGUgPW1lYW4obG9nMTAobWVhbl9wZXJjZW50X0ZlbWFsZSkpLCBtYWxlID0gbWVhbihsb2cxMChtZWFuX3BlcmNlbnRfTWFsZSkpKQoKbWVhbnMKYGBgCgpOb3RpY2UgaGVyZSB0aGF0IHRoZSBtZWFuIG9mIHRoZSBkaWZmZXJlbmNlcyB2YWx1ZSBpcyBpbmRlZWQgdGhlIHNhbWUgYXMgdGhlIGNvZWZmaWNpZW50IGFuZCB0aGUgJHQkLXZhbHVlIGFuZCB0aGUgJHAkLXZhbHVlIG1hdGNoLiBUaGUgJFxiZXRhX3sxfSQgY29lZmZpY2llbnQgdmFsdWUgKHNsb3BlKSBtYXRjaGVzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG1lYW5zIHZhbHVlIGNhbGN1YXRlZCBpbiAkdCQtdGVzdC4gVGhlIGludGVyY2VwdCBjb2VmZmljaWVudCAkXGJldGFfezB9JCB2YWx1ZSBvZiAxLjU2ICh3aGVuIHNleCBpcyB6ZXJvIG9yIGZlbWFsZSkgYWxzbyBtYXRjaGVzIHRoZSBtZWFuIHZhbHVlIGZvciB0aGUgZmVtYWxlIGdyb3VwIHdoZW4gY2FsY3VsYXRlZCBzZXBhcmF0ZWx5LiAKCiMjIyBJbmZsdWVuY2Ugb2YgYWdlIG9uIGRpZXRhcnkgb3V0Y29tZXMKCk5vdyB3ZSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgaW5mbHVlbmNlIG9mIGFnZSBncm91cCBvbiBkaWV0YXJ5IGNvbnN1bXB0aW9uLiAKCklmIHdlIHdhbnRlZCB0byB0ZXN0IHRoZSBoeXBvdGhlc2lzIHRoYXQgdGhlcmUgYXJlIGFueWdyb3VwIGRpZmZlcmVuY2VzLCB0aGF0IGF0IGxlYXN0IG9uZSBvZiB0aGUgZ3JvdXBzIGlzIGRpZmZlcmVudCBmcm9tIHRoZSBvdGhlcnM7IHdlIGNvdWxkIHVzZSBhbiBBTk9WQSB0ZXN0LgoKSXQgdHVybnMgb3V0IHRoYXQgQU5PVkFzIGFyZSBhbHNvIGEgc3BlY2lhbGl6ZWQgZm9ybSBvZiByZWdyZXNzaW9uLgoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgaG93IHRoZSBjb25zdW1wdGlvbiBvZiBmcnVpdHMgdmFyaWVzIGJ5IGFnZSBncm91cC4KCmBgYHtyfQoKc3VtbWFyeShhb3YobG9nMTAocHVsbChmaWx0ZXIoc2VwX2FnZV9kaWV0X2RhdGEsIGZvb2QgPT0gImZydWl0cyIpLCAKICAgICAgICAgICAgICAgbWVhbikpIH4gCiAgICBwdWxsKGZpbHRlcihzZXBfYWdlX2RpZXRfZGF0YSwgZm9vZCA9PSAiZnJ1aXRzIiksCiAgICAgICAgIGFnZV9ncm91cF9uYW1lKSkpCgpzZXBfYWdlX2RpZXRfZGF0YSU+JQogIGZpbHRlcihmb29kID09ICJmcnVpdHMiKSAlPiUgIAogIGxtKGxvZzEwKG1lYW4pIH5hZ2VfZ3JvdXBfbmFtZSwgZGF0YT0gLikgJT4lCiAgc3VtbWFyeSgpCgpgYGAKCgojIyMgSW5mbHVlbmNlIG9mIHJlZ2lvbiBvbiBkaWV0YXJ5IG91dGNvbWVzCgogCgoKCiMjIERhdGEgVmlzdWFsaXphdGlvbgoKIyMgU3VtbWFyeQoKCk5leHQsIHdlIHdhbnQgdG8gcHJvcG9zZSBvdXIgaWRlYSBmb3IgYSBzZWNvbmQgY2FzZSBzdHVkeSBpbiB0aGUgc2FtZSBmb2N1cyBhcmVhIG9mOiAKCi0gUXVlc3Rpb246IEhvdyBkbyBkaWV0cyAoY29uc3VtcHRpb24gb2YgdmFyaW91cyBtYWpvciBmb29kcyBhbmQgbnV0cmllbnRzKSBkaWZmZXIgYnkgcmVnaW9ucyAoZS5nLiBsb3ctaW5jb21lIGNvdW50cmllcyB2cyBub3QpIGFuZCBieSBnZW5kZXIgYXJvdW5kIHRoZSB3b3JsZD8gV2hhdCBpcyB0aGUgaW1wYWN0IG9mIHRoZSBkaWZmZXJlbnQgZGlldHMgb24gbW9ydGFsaXR5IG9yIGxpZmUgZXhwZWN0YW5jeT8KLSBEZXNjcmlwdGlvbjogV2Ugd291bGQgdGFrZSBzb21lIG9mIHRoZSBtYWluIHJlc3VsdHMgZnJvbSB0aGlzIHBhcGVyIChodHRwczovL3d3dy50aGVsYW5jZXQuY29tL2pvdXJuYWxzL2xhbmNldC9hcnRpY2xlL1BJSVMwMTQwLTY3MzYoMTkpMzAwNDEtOC9mdWxsdGV4dCl7dGFyZ2V0PSJfYmxhbmsifSBhbmQgaGlnaGxpZ2h0IHRoZW0gaW4gYSBjYXNlIHN0dWR5IChzaW1pbGFyIHRvIGJlZm9yZSBub3QgdHJ5aW5nIHRvIHJlcHJvZHVjZSB0aGUgYW5hbHlzaXMpLiBUaGlzIHBhcGVyIHNob3dzIHRoZSBsZWFkaW5nIGRpZXRhcnkgcmlzayBmYWN0b3JzIGZvciBtb3J0YWxpdHkgaW5jbHVkZWQgaGlnaCBpbnRha2Ugb2Ygc29kaXVtLCBsb3cgaW50YWtlIG9mIHdob2xlIGdyYWlucywgYW5kIGxvdyBpbnRha2Ugb2YgZnJ1aXRzLiAKLSBXaHkgaXMgdGhpcyBpbXBvcnRhbnQ/IFRoaXMgYW5hbHlzaXMgZGVtb25zdHJhdGVzIHRoZSBuZWVkIHRvIGltcHJvdmUgZGlldCBhY3Jvc3MgbmF0aW9ucyBhbmQgaW5mb3JtIGltcGxlbWVudGF0aW9uIG9mIGV2aWRlbmNlLWJhc2VkIGRpZXRhcnkgaW50ZXJ2ZW50aW9ucy4gCi0gRGF0YTogVGhpcyB0aGUgbGluayBKZXNzIEZhbnpvIHNlbnQgdXMgKGh0dHBzOi8vdml6aHViLmhlYWx0aGRhdGEub3JnL2diZC1jb21wYXJlLyl7dGFyZ2V0PSJfYmxhbmsifSwgYnV0IHdlIGhhZCB0byB0cmFjayBkb3duIGEgc3BlY2lmaWMgc2V0IG9mIGZpbGVzIHRoYXQgd2VyZSBub3QgaW5jbHVkZWQgaW4gdGhlIGxpbmsgdG8gYmUgYWJsZSB0byBkbyB0aGlzIGFuYWx5c2lzLiBUaGVzZSBmaWxlcyB3ZXJlIHNlbnQgdG8gdXMgaW4gYSBDU1YgZm9ybWF0IGFuZCB3ZSBoYXZlIGJlZW4gZ2l2ZW4gcGVybWlzc2lvbiB0byBob3N0IHRoZW0gYXMgcGFydCBvZiBvdXIgY2FzZSBzdHVkeSBhbmQganVzdCBjaXRlIHRoZSBvcmlnaW5hbCBzdHVkeS4gCi0gTWFqb3IgRGF0YSBTY2llbmNlIE9iamVjdGl2ZXM6IAoxKSBzY3JhcGluZyBkYXRhIChnYXBtaW5kZXIpICMgcHJvYmFibHkgbm90IGFueW1vcmUKMikgbG9hZGluZyBkYXRhIGZyb20gZGF0YSBwYWNrYWdlIAozKSB3cmFuZ2xpbmcgLSBqb2luaW5nIGRwbHlyIAo0KSB2aXN1YWxpemF0aW9uIC0gZ2dwbG90IAotIFN0YXRpc3RpY3Mgb2JqZWN0aXZlczogV2UgYXJlIGN1cnJlbnRseSB0b3JuIGJldHdlZW4gZGVtb25zdHJhdGluZyBsaW5lYXIgcmVncmVzc2lvbiBvciBmYWN0b3IgYW5hbHlzaXMuIE9uY2Ugd2Ugc3RhcnQgdGhlIGNhc2Ugc3R1ZHksIGl0IHdpbGwgYmUgZWFzaWVyIGZvciB1cyB0byB1bmRlcnN0YW5kLiBXZeKAmWxsIGtlZXAgeW91IHBvc3RlZCBvbiB0aGF0LiAKIyB0byBnZXQgYSByYXRpbyBvZiB2ZWdnaWUgY29uc3VtcHRpb246IFZlZ2dpZXMkbWVhbi8yNTAgKjEwMAojaHR0cHM6Ly93d3cuZ3VydTk5LmNvbS9yLWFub3ZhLXR1dG9yaWFsLmh0bWwKClRvIGRvIHRoaXMgd2UgbmVlZCB0byBjaGVjayBpZiBvdXIgZGF0YSB2aW9sYXRlcyB0aGUgYXNzdW1wdGlvbnMgdGhhdCB0aGVzZSBzdGF0aXN0aWNhbCB0ZXN0IHJlbHkgb24gaW4gb3JkZXIgdG8gY2hvb3NlIHRoZSBhcHByb3ByaWF0ZSB0ZXN0IHRvIGNvbXBhcmUgZ3JvdXBzLgo=